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

Leaner Docker image through the use of multi-stage builds #51

Merged
merged 1 commit into from
Mar 22, 2018

Conversation

brandur-stripe
Copy link
Contributor

@brandur-stripe brandur-stripe commented Mar 21, 2018

In #50 I was able to successfully push an image to Docker Hub, but quite
a large one -- weighing in at 91 MB, which is pretty heavy for this
small program. It's big because it includes the entire Go build system.

Here we lean out the final image by switching Dockerfile to use a
multi-phase build strategy. This creates one image initially based off
of a Go image which is used to build the final release program, then
creates a second image based on the lightweight Alpine Linux and copies
over the release binary.

This has the effect of reducing the final image's size from 91 MB to a
lean 13.7 MB (that's Alpine Linux + stripe-mock), which is faster/cheaper
for users to pull.

A smaller optimization is to add a .dockerignore file which prevents
us from having to copy a number of extraneous files into the Docker
daemon for the initial build. This will help nominally to speed things
up.

One slight loss is that I've removed testing within the Go image from
.travis.yml because we no longer have a Go runtime with which to run
go test ./.... I think this is okay because we're already running
tests elsewhere in the Travis build, and it's unlikely that running them
in a Docker container is going to surface anything extra.

Here's me running the image locally:

$ docker run -d --name stripe-mock-container -p 12112:12111 stripemock/stripe-mock
bc71abebe5f6d80a9af2d1d53c86777d8c50b2e9a8d4de4a8b25d66c32a5d44b

$ docker ps
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS                    NAMES
bc71abebe5f6        stripemock/stripe-mock   "/bin/sh -c /stripe-…"   26 seconds ago      Up 28 seconds       0.0.0.0:12112->12111/tcp stripe-mock-container

And a successful cURL:

$ curl http://localhost:12112
{
  "error": {
    "message": "Please authenticate by specifying an `Authorization` header with any valid looking testmode secret API key. For example, `Authorization: Bearer sk_test_123`. Authorization was ''.",
    "type": "invalid_request_error"
  }
}

r? @ob-stripe
cc @stripe/api-libraries

In #50 I was able to successfully push an image to Docker Hub, but quite
a large one -- weighing in at 91 MB, which is pretty heavy for this
small program.

Here we lean out the final image by switching `Dockerfile` to use a
multi-phase build strategy. This creates one image initially based off
of a Go image which is used to build the final release program, then
creates a second image based on the lightweight Alpine Linux and copies
over the release binary.

This has the effect of reducing the final image's size from 91 MB to a
lean 13.7 MB, which is faster/cheaper for users to pull.

A smaller optimization is to add a `.dockerignore` file which prevents
us from having to copy a number of extraneous files into the Docker
daemon for the initial build. This will help nominally to speed things
up.

One slight loss is that I've removed testing within the Go image from
`.travis.yml` because we no longer have a Go runtime with which to run
`go test ./...`. I think this is okay because we're already running
tests elsewhere in the Travis build, and it's unlikely that running them
in a Docker container is going to surface anything extra.

Here's me running the image locally:

```
$ docker run -d --name stripe-mock-container -p 12112:12111 stripemock/stripe-mock
bc71abebe5f6d80a9af2d1d53c86777d8c50b2e9a8d4de4a8b25d66c32a5d44b

$ docker ps
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS                    NAMES
bc71abebe5f6        stripemock/stripe-mock   "/bin/sh -c /stripe-…"   26 seconds ago      Up 28 seconds       0.0.0.0:12112->12111/tcp stripe-mock-container
```

And a successful cURL:

```
$ curl http://localhost:12112
{
  "error": {
    "message": "Please authenticate by specifying an `Authorization` header with any valid looking testmode secret API key. For example, `Authorization: Bearer sk_test_123`. Authorization was ''.",
    "type": "invalid_request_error"
  }
}
```
Copy link
Contributor

@ob-stripe ob-stripe left a comment

Choose a reason for hiding this comment

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

This is awesome. :shipit:

@brandur-stripe brandur-stripe merged commit 1644ab8 into master Mar 22, 2018
@brandur-stripe brandur-stripe deleted the brandur-leaner-docker branch March 22, 2018 00:46
@brandur-stripe
Copy link
Contributor Author

And actually, Docker Hub reports that the compressed side is 6 MB even! Big improvement.

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.

3 participants