Skip to content

Commit

Permalink
feat: always pull latest image (#1267)
Browse files Browse the repository at this point in the history
## Description:
Prior to this PR, Kurtosis would use the local image if it was
available, and if it wasn't, pulled the image from Dockerhub (or other
container registry). This PR reverses that behavior by always attempting
to pull the latest image, and using the local image, if available, only
if the pull fails. For users, this means they will always be using the
latest version of the images they're working with.

Through testing, I've determined the impact on speed is negligible but
I've kept a `FetchLocalImage` function with the old behavior in case we
need to rollback this change. I've also removed a redundant `FetchImage`
from the `StartServices` as it is already being called for each service
during validation phase and in `CreateAndStartContainerArgs`.

## Is this change user facing?
NO

## References
#1103
  • Loading branch information
tedim52 committed Sep 8, 2023
1 parent 69a8e61 commit 6706809
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 12 deletions.
Expand Up @@ -228,11 +228,6 @@ func CreateEngine(
labelStrs,
).Build()

// Best-effort pull attempt
if err = dockerManager.FetchImage(ctx, containerImageAndTag); err != nil {
logrus.Warnf("Failed to pull the latest version of engine server image '%v'; you may be running an out-of-date version", containerImageAndTag)
}

containerId, hostMachinePortBindings, err := dockerManager.CreateAndStartContainer(ctx, createAndStartArgs)
if err != nil {
return nil, stacktrace.Propagate(err, "An error occurred starting the Kurtosis engine container")
Expand Down
Expand Up @@ -692,11 +692,6 @@ func createStartServiceOperation(

createAndStartArgs := createAndStartArgsBuilder.Build()

// Best-effort pull attempt
if err = dockerManager.FetchImage(ctx, containerImageName); err != nil {
logrus.Warnf("Failed to pull the latest version of user service container image '%v'; you may be running an out-of-date version", containerImageName)
}

containerId, hostMachinePortBindings, err := dockerManager.CreateAndStartContainer(ctx, createAndStartArgs)
if err != nil {
return nil, stacktrace.Propagate(err, "An error occurred starting the user service container for user service with UUID '%v'", serviceUUID)
Expand Down
Expand Up @@ -1121,6 +1121,9 @@ func (manager *DockerManager) GetContainersByLabels(ctx context.Context, labels
return result, nil
}

// [FetchImage] always attempts to retrieve the latest [dockerImage].
// If retrieving the latest [dockerImage] fails, the local image will be used.
// Returns error, if no local image is available after retrieving latest fails.
func (manager *DockerManager) FetchImage(ctx context.Context, dockerImage string) error {
// if the image name doesn't have version information we concatenate `:latest`
// this behavior is similar to CreateAndStartContainer above
Expand All @@ -1135,6 +1138,42 @@ func (manager *DockerManager) FetchImage(ctx context.Context, dockerImage string
}
logrus.Tracef("Is image available locally?: %v", doesImageExistLocally)

// try and pull latest image even if image exists locally
if doesImageExistLocally {
logrus.Tracef("Image exists locally, but attempting to get latest from remote image repository.")
err = manager.pullImage(ctx, dockerImage)
if err != nil {
logrus.Tracef("Failed to pull Docker image '%v' from remote image repository. Going to use available local image.", dockerImage)
} else {
logrus.Tracef("Latest image successfully pulled from remote to local.")
}
} else {
err = manager.pullImage(ctx, dockerImage)
if err != nil {
return stacktrace.Propagate(err, "Failed to pull Docker image '%v' from remote image repository.", dockerImage)
}
}

return nil
}

// [FetchLocalImage] uses the local [dockerImage] if it's available.
// If unavailable, will attempt to fetch the latest image.
// Returns error if local [dockerImage] is unavailable and pulling image fails.
func (manager *DockerManager) FetchLocalImage(ctx context.Context, dockerImage string) error {
// if the image name doesn't have version information we concatenate `:latest`
// this behavior is similar to CreateAndStartContainer above
// this allows us to be deterministic in our behaviour
if !strings.Contains(dockerImage, dockerTagSeparatorChar) {
dockerImage = dockerImage + dockerTagSeparatorChar + dockerDefaultTag
}
logrus.Tracef("Checking if image '%v' is available locally...", dockerImage)
doesImageExistLocally, err := manager.isImageAvailableLocally(ctx, dockerImage)
if err != nil {
return stacktrace.Propagate(err, "An error occurred checking for local availability of Docker image '%v'", dockerImage)
}
logrus.Tracef("Is image available locally?: %v", doesImageExistLocally)

if !doesImageExistLocally {
logrus.Tracef("Image doesn't exist locally, so attempting to pull it...")
err = manager.pullImage(ctx, dockerImage)
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/faq.md
Expand Up @@ -22,15 +22,15 @@ Great question, check out our [roadmap page](./roadmap.md) for the latest detail

Why am I getting rate limited by Dockerhub when pulling images?
---------------------------------------------------------------
Kurtosis will first try to use your locally cached container images before pulling any image from Dockerhub. If you are getting rate limited by Dockerhub when pulling images, it likely means you have exceeded the [limits set by Docker](https://docs.docker.com/docker-hub/download-rate-limit/).
If you are getting rate limited by Dockerhub when pulling images, it likely means you have exceeded the [limits set by Docker](https://docs.docker.com/docker-hub/download-rate-limit/).

Does Kurtosis support other container registries or libraries?
--------------------------------------------------------------
Currently, Kurtosis supports any public container registry (Dockerhub, Google Cloud Container Registry, etc.). If your project or team requires using a private container registry, please let us know by [filing an issue in our Github](https://github.com/kurtosis-tech/kurtosis/issues/new?assignees=&labels=feature+request&projects=&template=feature-request.yml) or letting us know in [Discord](https://discord.gg/jJFG7XBqcY).

Does Kurtosis pull a container image down each time I run a package?
--------------------------------------------------------------------
Kurtosis will always first check the local cache for a given container image for each `kurtosis run` before pulling the image from an external registry (e.g. Dockerhub).
Kurtosis will always attempt to pull the latest image from an external registry (e.g. Dockerhub) for each `kurtosis run`. If the image pull fails and the image exists locally, Kurtosis will use the local image.

Will Kurtosis be able to run my package remotely from a private Github repository?
----------------------------------------------------------------------------------
Expand Down

0 comments on commit 6706809

Please sign in to comment.