Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parallelize image mirroring and reuse mounted layers #19017

Merged
merged 2 commits into from
Mar 30, 2018

Conversation

smarterclayton
Copy link
Contributor

@smarterclayton smarterclayton commented Mar 19, 2018

Linear execution of large mirrors doesn't make sense. Create an execution plan that can be run in parallel and also supports dry run.

$ cat /tmp/file2
docker.io/openshift/origin:v3.9 registry.svc.ci.openshift.org/ci/test1:v3.9
docker.io/openshift/origin:v3.9 registry.svc.ci.openshift.org/ci/test2:v3.9
docker.io/openshift/origin:v3.10 registry.svc.ci.openshift.org/ci/test1:v3.10
docker.io/openshift/origin:v3.10 registry.svc.ci.openshift.org/ci/test2:v3.10
$ oc image mirror -f /tmp/file2
registry.svc.ci.openshift.org/
  ci/test1
    blobs:
      docker.io/openshift/origin sha256:514a97903be7e078bd811bf37fd5716ee8f24fe10a5ba7df4328d13c4cd112bb 262B
      docker.io/openshift/origin sha256:910e88f98b9f323081f8650f2f18f7173cb1dd3cc0d6e720968fcf72d14c89d8 262B
      docker.io/openshift/origin sha256:ce242a29d50867ad0bde94539b48b6f23c9c2757eaf7e6b7841498ae0019b7cb 2.639KiB
      docker.io/openshift/origin sha256:303a374f1b63bb18cb81008d151128fd2bea8bdd22a31ec0b7d328d6179cb48b 2.64KiB
      docker.io/openshift/origin sha256:963bdd7dfde6f82b11cb6e9216ab77b3ee874fb28008f38416bd1fb2b313ae6e 61.42MiB
      docker.io/openshift/origin sha256:92f5eb04e64965f468424081a7fc8d5b68b825d83246c09eb9bed12bd726f782 61.42MiB
      docker.io/openshift/origin sha256:5e35d10a3ebadf9d6ab606ce72e1e77f8646b2e2ff8dd3a60d4401c3e3a76f31 69.6MiB
      docker.io/openshift/origin sha256:1f6ecdfa27d59eeffd78055c9f2846444f1d24a5422789c20aa70adaf1deec4c 139.2MiB
      docker.io/openshift/origin sha256:fc90d30a5389d9f5e851664952d5aee2a828b3ffe6211e2bb16b21f9c15b6a93 182.4MiB
    manifests:
      sha256:004e7ef81f386f648f023c5838ef38562d07f5d25cc3dab87008f33c49a99412 -> v3.9
      sha256:0a0ba0705f0d7be46746619b705a138c71f74f6a3a6924d69d1517a504d85c6c -> v3.10
  ci/test2
    blobs:
      docker.io/openshift/origin sha256:514a97903be7e078bd811bf37fd5716ee8f24fe10a5ba7df4328d13c4cd112bb 262B
      docker.io/openshift/origin sha256:910e88f98b9f323081f8650f2f18f7173cb1dd3cc0d6e720968fcf72d14c89d8 262B
      docker.io/openshift/origin sha256:ce242a29d50867ad0bde94539b48b6f23c9c2757eaf7e6b7841498ae0019b7cb 2.639KiB
      docker.io/openshift/origin sha256:303a374f1b63bb18cb81008d151128fd2bea8bdd22a31ec0b7d328d6179cb48b 2.64KiB
      docker.io/openshift/origin sha256:963bdd7dfde6f82b11cb6e9216ab77b3ee874fb28008f38416bd1fb2b313ae6e 61.42MiB
      docker.io/openshift/origin sha256:92f5eb04e64965f468424081a7fc8d5b68b825d83246c09eb9bed12bd726f782 61.42MiB
      docker.io/openshift/origin sha256:5e35d10a3ebadf9d6ab606ce72e1e77f8646b2e2ff8dd3a60d4401c3e3a76f31 69.6MiB
      docker.io/openshift/origin sha256:1f6ecdfa27d59eeffd78055c9f2846444f1d24a5422789c20aa70adaf1deec4c 139.2MiB
      docker.io/openshift/origin sha256:fc90d30a5389d9f5e851664952d5aee2a828b3ffe6211e2bb16b21f9c15b6a93 182.4MiB
    manifests:
      sha256:004e7ef81f386f648f023c5838ef38562d07f5d25cc3dab87008f33c49a99412 -> v3.9
      sha256:0a0ba0705f0d7be46746619b705a138c71f74f6a3a6924d69d1517a504d85c6c -> v3.10
  stats: shared=9 unique=0 size=514.1MiB ratio=0.00

phase 0:
  registry.svc.ci.openshift.org ci/test1
    blobs=9 mounts=0 manifests=2 shared=9
phase 1:
  registry.svc.ci.openshift.org ci/test2
    blobs=9 mounts=9 manifests=2 shared=9

info: Planning completed in 1.78s
sha256:0a0ba0705f0d7be46746619b705a138c71f74f6a3a6924d69d1517a504d85c6c registry.svc.ci.openshift.org/ci/test1:v3.10
sha256:004e7ef81f386f648f023c5838ef38562d07f5d25cc3dab87008f33c49a99412 registry.svc.ci.openshift.org/ci/test1:v3.9
sha256:004e7ef81f386f648f023c5838ef38562d07f5d25cc3dab87008f33c49a99412 registry.svc.ci.openshift.org/ci/test2:v3.9
sha256:0a0ba0705f0d7be46746619b705a138c71f74f6a3a6924d69d1517a504d85c6c registry.svc.ci.openshift.org/ci/test2:v3.10
info: Mirroring completed in 3.01s

@openshift-ci-robot openshift-ci-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. approved Indicates a PR has been approved by an approver from all required OWNERS files. labels Mar 19, 2018
@openshift-ci-robot openshift-ci-robot added the size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. label Mar 19, 2018
@openshift-ci-robot openshift-ci-robot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Mar 19, 2018
@openshift-merge-robot openshift-merge-robot added the vendor-update Touching vendor dir or related files label Mar 20, 2018
@smarterclayton smarterclayton force-pushed the plan branch 3 times, most recently from b9fbba2 to 1a15970 Compare March 22, 2018 03:38
@smarterclayton smarterclayton changed the title WIP - Create an execution plan for mirroring in parallel Create an execution plan for mirroring in parallel Mar 22, 2018
@openshift-ci-robot openshift-ci-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Mar 22, 2018
@smarterclayton
Copy link
Contributor Author

@bparees pretty raw but getting close. I'm working through some quay bugs / inconsistencies right now.

Example: fmt.Sprintf(loginExample, name+" login"),
Run: func(c *cobra.Command, args []string) {
o.Out = out
o.ErrOut = errOut
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move these up:

o := &Options{Out: out, ErrOut: errOut}

if err != nil {
return err
}
o.Namespaces = []string{ns, "openshift"}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't that be configurable with openshift being the default?

o.Out = out
o.ErrOut = errOut
kcmdutil.CheckErr(o.Complete(f, args))
kcmdutil.CheckErr(o.Run())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're missing

kcmdutil.CheckErr(o.Validate())

if o.Check {
ctx := apirequest.NewContext()
if !public && !o.ShowInternal {
fmt.Fprintf(o.ErrOut, "info: Registry does not have a public hostname registered\n")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/info/warning

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not a warning, you can run this inside a cluster successfully.

`)
)

type Credentials struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be better to use k8s.io/kubernetes/pkg/credentialprovider.DockerConfigJson instead? Although it contains only reading bits for dockerfile it's still relevant, imho.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is about holding credentials from interior code to output, but not actually serializing the data. We direct modify JSON to avoid dropping fields.

Example: fmt.Sprintf(loginExample, name+" login"),
Run: func(c *cobra.Command, args []string) {
o.Out = out
o.ErrOut = errOut
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as before.

Run: func(c *cobra.Command, args []string) {
o.Out = out
o.ErrOut = errOut
kcmdutil.CheckErr(o.Complete(f, args))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again missing Validate call.


os::test::junit::declare_suite_start "cmd/registry/info"
os::cmd::expect_success "oc registry info"
os::cmd::expect_failure_and_text "oc registry info --internal --public" "only one of --internal or --public"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd expect a bit more tests, to be honest ;)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are all in a different PR, but registry info is difficult to test with our existing framework because it requires master reconfig

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on #18930

@openshift-bot openshift-bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 22, 2018
Allows tokens that cover the scope to be reused
@openshift-bot openshift-bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 22, 2018
@smarterclayton smarterclayton changed the title Create an execution plan for mirroring in parallel Parallelize image mirroring and reuse mounted layers Mar 22, 2018
@smarterclayton
Copy link
Contributor Author

/test cross

@smarterclayton
Copy link
Contributor Author

/retest
/test cross

Copy link
Contributor

@soltysh soltysh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left you some comments.

flag.BoolVar(&o.Force, "force", o.Force, "If true, attempt to write all contents.")
flag.BoolVar(&o.Force, "force", o.Force, "Attempt to write all layers and manifests even if they exist in the remote repository.")
flag.IntVar(&o.MaxRegistry, "max-registry", 4, "Number of concurrent registries to connect to at any one time.")
flag.IntVar(&o.MaxPerRegistry, "max-per-registry", 6, "Number of concurrent requests allowed per registry.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

req-per-registry? The current naming is confusing with max-registry imo.

}

func (o *pushOptions) Repository(ctx apirequest.Context, context *registryclient.Context, creds auth.CredentialStore, t DestinationType, ref imageapi.DockerImageReference) (distribution.Repository, error) {
func (o *pushOptions) Repository(ctx apirequest.Context, context *registryclient.Context, t DestinationType, ref imageapi.DockerImageReference) (distribution.Repository, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a helper function can you make it private?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's on a private type, which means it's not visible outside the package.

tabw := tabwriter.NewWriter(o.ErrOut, 0, 0, 1, ' ', 0)
for i := range work.phases {
phase := &work.phases[i]
fmt.Fprintf(o.ErrOut, "phase %d:\n", i)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug? If so please use glog.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, deliberate output for a human that is exceptional (not the key output)

tabw.Flush()
}
fmt.Fprintln(o.ErrOut)
fmt.Fprintf(o.ErrOut, "info: Planning completed in %s\n", time.Now().Sub(start).Round(10*time.Millisecond))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why you're using ErrOut for majority of the outputs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because these are informational, not structured output intended for the tool.

To offer the best possible bulk upload story, we should look for mount
opportunities when we evaluate our mirror targets and send them in
order. Also use paralellization and add dry run support.
@openshift-ci-robot openshift-ci-robot added the lgtm Indicates that a PR is ready to be merged. label Mar 30, 2018
Copy link
Contributor

@soltysh soltysh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm

@openshift-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: smarterclayton, soltysh

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-merge-robot openshift-merge-robot merged commit b68ddd7 into openshift:master Mar 30, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. vendor-update Touching vendor dir or related files
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants