Skip to content

Made fixes and optimizations to encryption GC#3430

Merged
estesp merged 4 commits intocontainerd:masterfrom
lumjjb:encgcfix
Jul 22, 2019
Merged

Made fixes and optimizations to encryption GC#3430
estesp merged 4 commits intocontainerd:masterfrom
lumjjb:encgcfix

Conversation

@lumjjb
Copy link
Copy Markdown
Contributor

@lumjjb lumjjb commented Jul 18, 2019

There are some fixes required for garbage collection, as well as some optimizations for removal of certain resources from the lease for the image encryption feature introduced in #3134.

This PR aims to fix these known GC issues.

Signed-off-by: Brandon Lum [email protected]

@stefanberger
Copy link
Copy Markdown
Contributor

stefanberger commented Jul 18, 2019

This PR fixes an issue I had seen with this command line:

./bin/ctr images rm ubuntuenc:1 ; ./bin/ctr images pull --all-platforms docker.io/library/ubuntu:16.04 ; sleep 0 ; while :; do ./bin/ctr images encrypt --recipient mypubkey.pem docker.io/library/ubuntu:16.04 ubuntuenc:1 && ./bin/ctr images export ubuntuenc.tgz ubuntuenc:1 && ./bin/ctr images rm ubuntuenc:1 || break; done

Tested-by: Stefan Berger [email protected]

@theopenlab-ci
Copy link
Copy Markdown

theopenlab-ci Bot commented Jul 18, 2019

Build succeeded.

@theopenlab-ci
Copy link
Copy Markdown

theopenlab-ci Bot commented Jul 18, 2019

Build succeeded.

@dmcgowan
Copy link
Copy Markdown
Member

Ok, I think I see what is going wrong here. Normally the client is responsible for providing leases through the context and that lease will be used anywhere content is created. Explicitly adding to the lease here is not necessary (it is only needed in read case when you want to consume some content you did not create and want to ensure your operation completes without something else deleting it).

In this case, the lease should be created at the highest client level, ctr
Try adding

		ctx, done, err := client.WithLease(ctx)
		if err != nil {
			return err
		}
		defer done(ctx)

in your commands before calling down into your code which creates resources. This will ensure everything is kept around during the life of your client command.

@codecov-io
Copy link
Copy Markdown

codecov-io commented Jul 18, 2019

Codecov Report

Merging #3430 into master will increase coverage by <.01%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #3430      +/-   ##
==========================================
+ Coverage   44.24%   44.24%   +<.01%     
==========================================
  Files         123      123              
  Lines       13675    13675              
==========================================
+ Hits         6050     6051       +1     
+ Misses       6694     6693       -1     
  Partials      931      931
Flag Coverage Δ
#linux 48.05% <ø> (ø) ⬆️
#windows 39.78% <ø> (ø) ⬆️
Impacted Files Coverage Δ
runtime/v2/shim/shim_windows.go 43.5% <0%> (+0.64%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5631fe3...c118c45. Read the comment docs.

@lumjjb
Copy link
Copy Markdown
Contributor Author

lumjjb commented Jul 18, 2019

@dmcgowan That's nice! Let me make a change to that as well in this PR then!

@theopenlab-ci
Copy link
Copy Markdown

theopenlab-ci Bot commented Jul 18, 2019

Build succeeded.

@stefanberger
Copy link
Copy Markdown
Contributor

Works for me...

@theopenlab-ci
Copy link
Copy Markdown

theopenlab-ci Bot commented Jul 18, 2019

Build succeeded.

@lumjjb
Copy link
Copy Markdown
Contributor Author

lumjjb commented Jul 18, 2019

The test failing is

--- FAIL: TestImageIsUnpacked (0.35s)
...
    image_test.go:65: image should not be unpacked

I am able to make it go away by removing the use of the lease from the encryption test, but I'm not sure if this is the expected behavior for leases.
EDIT: unable -> able typo

    ctx, done, err := client.WithLease(ctx)
    if err != nil {
        t.Fatal(err)
    }
    defer done(ctx)

@theopenlab-ci
Copy link
Copy Markdown

theopenlab-ci Bot commented Jul 18, 2019

Build succeeded.

Comment thread images/encryption/encryption.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

don't call cw.Digest() here, it should be called after Commit

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ok

Comment thread image_enc_test.go Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This test doesn't need a lease such as WithLease?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ok - i think i figured out what the issue was. I think it is a bad gc label.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Pushing a fix 🤞 .

@theopenlab-ci
Copy link
Copy Markdown

theopenlab-ci Bot commented Jul 18, 2019

Build succeeded.

@theopenlab-ci
Copy link
Copy Markdown

theopenlab-ci Bot commented Jul 18, 2019

Build succeeded.

@lumjjb
Copy link
Copy Markdown
Contributor Author

lumjjb commented Jul 18, 2019 via email

@theopenlab-ci
Copy link
Copy Markdown

theopenlab-ci Bot commented Jul 19, 2019

Build succeeded.

@theopenlab-ci
Copy link
Copy Markdown

theopenlab-ci Bot commented Jul 19, 2019

Build succeeded.

@lumjjb
Copy link
Copy Markdown
Contributor Author

lumjjb commented Jul 19, 2019

@stefanberger @dmcgowan

Yea, it does seem like the issue is that the tests are interacting with each other because certain things are not being deleted from the content store that were being leased. Since the client.WithLeases call, doesn't have the leases.SynchronousDelete option, if the order is

  • delete image
  • release lease

The content will not be deleted unless GC runs. We've found 2 patches that work, @dmcgowan let us know what your thoughts are.

diff --git a/lease.go b/lease.go
index d46b79d..2bdf878 100644
--- a/lease.go
+++ b/lease.go
@@ -41,6 +41,6 @@ func (c *Client) WithLease(ctx context.Context) (context.Context, func(context.C

        ctx = leases.WithLease(ctx, l.ID)
        return ctx, func(ctx context.Context) error {
-               return ls.Delete(ctx, l)
+               return ls.Delete(ctx, l, leases.SynchronousDelete)
        }, nil
 }

OR

diff --git a/image_enc_test.go b/image_enc_test.go
index 9749971..97c2429 100644
--- a/image_enc_test.go
+++ b/image_enc_test.go
@@ -161,10 +161,15 @@ func TestImageEncryption(t *testing.T) {
                        Parameters: dcparameters,
                },
        }
+       // Clean up function cancels lease before deleting the image so the images are
+       // properly deleted
+       defer func() {
+               done(ctx)
+               client.ImageService().Delete(ctx, imageName, images.SynchronousDelete())
+               client.ImageService().Delete(ctx, encImageName, images.SynchronousDelete())
+       }()

        // Perform decryption of image
-       defer client.ImageService().Delete(ctx, imageName, images.SynchronousDelete())
-       defer client.ImageService().Delete(ctx, encImageName, images.SynchronousDelete())
        lf = func(desc ocispec.Descriptor) bool {
                return true
        }

Comment thread image_enc_test.go Outdated
// properly deleted
defer func() {
done(ctx)
client.ImageService().Delete(ctx, imageName, images.SynchronousDelete())
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would definitely encourage using test specific image names here. Also when doing a synchronous delete of 2 images, just add the flag on the second one.

@theopenlab-ci
Copy link
Copy Markdown

theopenlab-ci Bot commented Jul 22, 2019

Build succeeded.

@estesp
Copy link
Copy Markdown
Member

estesp commented Jul 22, 2019

I think it would make sense to just add some randomness to the encrypted image name; that way parallel runs of the suite won't overlap on name use. And we also pull a seed image at the start of test runs--busybox I think, so I'm not sure you need to absolutely pull or delete that image as you should be able to find it in the image service? @dmcgowan can correct me if I'm wrong on that.

@lumjjb
Copy link
Copy Markdown
Contributor Author

lumjjb commented Jul 22, 2019

I think it would make sense to just add some randomness to the encrypted image name;

@estesp I'm curious about that too - I was unsure about the implications for the unpacked image, seeing as how the actual unpacked image would have the same content hash even with a different tag... Let me try that out..

EDIT: I tried it out and it didn't work unfortunately... I tried it with this patch, that takes the pulled image and tags it as another image name.

diff --git a/image_enc_test.go b/image_enc_test.go
index 97c2429..d13853f 100644
--- a/image_enc_test.go
+++ b/image_enc_test.go
@@ -31,11 +31,12 @@ import (
        ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 )

-func setupBusyboxImage(t *testing.T) {
+func setupBusyboxImage(t *testing.T, testImageName string) {
        if runtime.GOOS == "windows" {
                t.Skip()
        }

+       //const imageName = "docker.io/library/nginx:latest"
        const imageName = "docker.io/library/busybox:latest"
        ctx, cancel := testContext(t)
        defer cancel()
@@ -46,6 +47,8 @@ func setupBusyboxImage(t *testing.T) {
        }
        defer client.Close()

+       s := client.ImageService()
+
        // Cleanup
        err = client.ImageService().Delete(ctx, imageName)
        if err != nil && !errdefs.IsNotFound(err) {
@@ -58,6 +61,19 @@ func setupBusyboxImage(t *testing.T) {
                t.Fatal(err)
        }

+       img, err := s.Get(ctx, imageName)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       img.Name = testImageName
+       _, err = s.Create(ctx, img)
+       if err != nil {
+               t.Fatalf("Unable to create image: %v", err)
+       }
+
+       image = NewImage(client, img)
+
        err = image.Unpack(ctx, DefaultSnapshotter)
        if err != nil {
                t.Fatal(err)
@@ -65,15 +81,16 @@ func setupBusyboxImage(t *testing.T) {
 }

 func TestImageEncryption(t *testing.T) {
-       setupBusyboxImage(t)
+       const imageName = "docker.io/library/encimgtest:enc-test"
+       const encImageName = "docker.io/library/encimgtest:enc-test-encrypted"
+
+       setupBusyboxImage(t, imageName)

        publicKey, privateKey, err := utils.CreateRSATestKey(2048, nil, true)
        if err != nil {
                t.Fatal(err)
        }

-       const imageName = "docker.io/library/busybox:latest"
-       const encImageName = "docker.io/library/busybox:enc"
        ctx, cancel := testContext(t)
        defer cancel()

@@ -164,9 +181,9 @@ func TestImageEncryption(t *testing.T) {
        // Clean up function cancels lease before deleting the image so the images are
        // properly deleted
        defer func() {
-               done(ctx)
-               client.ImageService().Delete(ctx, imageName, images.SynchronousDelete())
-               client.ImageService().Delete(ctx, encImageName, images.SynchronousDelete())
+               //done(ctx)
+               //client.ImageService().Delete(ctx, imageName, images.SynchronousDelete())
+               //client.ImageService().Delete(ctx, encImageName, images.SynchronousDelete())
        }()

        // Perform decryption of image

Copy link
Copy Markdown
Member

@dmcgowan dmcgowan left a comment

Choose a reason for hiding this comment

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

LGTM

This change is better than what is in master...

However, I think there are still some improvements which could be made to improve reliability. We have a "seed" image which gets pulled at the beginning so we can attempt to avoid pulling as much as possible during tests. In this case, it is OK to use that seed image, encrypt it, then decrypt it into a different image name, the original image does not need to be deleted at the end, only the newly created ones.

@lumjjb
Copy link
Copy Markdown
Contributor Author

lumjjb commented Jul 22, 2019

Sounds good - I'll start checking out the seed image in the meantime!

Copy link
Copy Markdown
Member

@estesp estesp left a comment

Choose a reason for hiding this comment

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

LGTM

@estesp estesp merged commit 49fdb9e into containerd:master Jul 22, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants