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

Handle pull for "internal" containers #990

Merged
merged 3 commits into from
Sep 25, 2017
Merged

Conversation

samuelkarp
Copy link
Contributor

@samuelkarp samuelkarp commented Sep 25, 2017

Summary

Internal containers should be treated differently during the pull step of the container lifecycle.

We currently have two types of internal containers: "empty host volume" containers and pause containers. "Empty host volume" containers should either be pulled from a remote image (as on Windows) or imported from a locally-generated tarball (as on Linux). The pause container image is either imported from a locally-embedded tarball inside the agent's rootfs or expected to already be present on the host (if the image is overridden via config).

A second commit here changes the empty host volume image on Windows from microsoft/windowsservercore:latest to microsoft/nanoserver:latest, as it's a significantly smaller image.

This addresses #729 (comment).

Implementation details

New constant exposed in the emptyvolume package to control whether or not the image is present locally to be imported, or it should be pulled. New logic in DockerTaskEngine to dispatch to different methods based on the container's Type field.

Testing

  • Builds on Linux (make release)
  • Builds on Windows (go build -out amazon-ecs-agent.exe ./agent)
  • Unit tests on Linux (make test) pass
  • Unit tests on Windows (go test -timeout=25s ./agent/...) pass
  • Integration tests on Linux (make run-integ-tests) pass
  • Integration tests on Windows (.\scripts\run-integ-tests.ps1) pass
  • Functional tests on Linux (make run-functional-tests) pass
  • Functional tests on Windows (.\scripts\run-functional-tests.ps1) pass

New tests cover the changes: yes

Description for the changelog

  • Bug - microsoft/windowsservercore:latest was not pulled on Windows under certain conditions

Licensing

This contribution is under the terms of the Apache 2.0 License: yes

Copy link
Contributor

@petderek petderek left a comment

Choose a reason for hiding this comment

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

Neat! Had a few comments but it looks good.

}

// Windows is special-cased here and just performs a normal pull
if runtime.GOOS == "windows" {
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 prefer this test to be in platform specific files if the expectations are different.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, wasn't sure about that since this is the only difference in all these tests. I can move it though.

Copy link
Contributor

Choose a reason for hiding this comment

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

Have this check at the top of the function and do a t.Skip() if you don't want to make a separate Linux file?

You could also make this more OO instead of using platform constants. That would make testing more straightforward here.

You could also just leave this as is. I don't have a strong preference.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Have this check at the top of the function and do a t.Skip() if you don't want to make a separate Linux file?

There's both a Linux- and Windows-test, sharing most of the test structure except some of the expectations.

You could also make this more OO instead of using platform constants.

Not sure I understand what you mean here.

Copy link
Contributor

Choose a reason for hiding this comment

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

You branch based on a constant boolean that's defined for each platform. You could instead attach these functions to a struct with this configuration embedded.

The tests would then be driven by configuration instead of driven by platform.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I went and separated them into platform-specific files.

@@ -508,6 +509,20 @@ func (engine *DockerTaskEngine) GetTaskByArn(arn string) (*api.Task, bool) {
}

func (engine *DockerTaskEngine) pullContainer(task *api.Task, container *api.Container) DockerContainerMetadata {
if container.Type == api.ContainerCNIPause {
// ContainerCNIPause images are managed at startup
return DockerContainerMetadata{}
Copy link
Contributor

Choose a reason for hiding this comment

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

This is redundant.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What part is redundant? The comment? That explains why there's an early return.

Copy link
Contributor

Choose a reason for hiding this comment

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

The whole if block doesn't seem necessary. The switch block that runs the same check.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh! Yeah...oops. Will remove!

case api.ContainerEmptyHostVolume:
// ContainerEmptyHostVolume image is either local (must be imported) or remote (must be pulled)
if emptyvolume.LocalImage {
return engine.client.ImportLocalEmptyVolumeImage()
Copy link
Contributor

Choose a reason for hiding this comment

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

Did create better describe what was happening behind the scenes here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Import is the verb that is used in the Docker API.

@jhaynes
Copy link
Contributor

jhaynes commented Sep 25, 2017

Can you edit CHANGELOG.md with the description of this change also?

@samuelkarp
Copy link
Contributor Author

@petderek @jhaynes Done, please take a look.

Copy link
Contributor

@petderek petderek left a comment

Choose a reason for hiding this comment

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

:shipit:

Copy link
Contributor

@vsiddharth vsiddharth left a comment

Choose a reason for hiding this comment

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

LGTM!
Had just a minor question ?

case resp := <-response:
return resp
case <-timeout:
return DockerContainerMetadata{Error: &DockerTimeoutError{pullImageTimeout, "pulled"}}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can the transition string be a const ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Any particular reason why? I generally like constants if there's string reuse, string comparison, or if it aids clarity. I suppose reuse might apply here, but it's only used in two places right now.

Copy link
Contributor

Choose a reason for hiding this comment

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

I was primarily concerned with reuse but it was more of a suggestion.

case resp := <-response:
return resp
case <-timeout:
return DockerContainerMetadata{Error: &DockerTimeoutError{pullImageTimeout, "pulled"}}
Copy link
Contributor

Choose a reason for hiding this comment

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

I was primarily concerned with reuse but it was more of a suggestion.

This commit treats internal containers differently during the pull step
of the container lifecycle.

We currently have two types of internal containers: "empty host volume"
containers and pause containers.  "Empty host volume" containers should
either be pulled from a remote image (as on Windows) or imported from a
locally-generated tarball (as on Linux).  The pause container image is
either imported from a locally-embedded tarball inside the agent's
rootfs or expected to already be present on the host (if the image is
overridden via config).
microsoft/nanoserver:latest is significantly smaller than
microsoft/windowsservercore:latest and should pull more quickly.
Copy link
Contributor

@aaithal aaithal left a comment

Choose a reason for hiding this comment

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

:shipit:

@samuelkarp samuelkarp merged commit 7a26f74 into aws:dev Sep 25, 2017
@jhaynes jhaynes mentioned this pull request Sep 30, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants