mirror of https://github.com/docker/docs.git
Update Golang section to 1.19 (PR 1 of 2) (#16867)
* Update index and build parts of Golang to v1.19 * Update Golang to 1.19 in the first of the two sample apps
This commit is contained in:
parent
d04fccbcd4
commit
25738b74b5
|
@ -8,53 +8,46 @@ redirect_from:
|
|||
|
||||
{% include_relative nav.html selected="1" %}
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* Some understanding of Go and its toolchain. This is not a tutorial on Go. If
|
||||
you are new to the language, the [Go website](https://golang.org/){: target="_blank" rel="noopener" class="_"}
|
||||
is a good starting point, so go (pun intended) check it out.
|
||||
* You understand basic [Docker concepts](../../get-started/overview.md).
|
||||
* You're familiar with the [Dockerfile format](../../build/building/packaging.md#dockerfile).
|
||||
* You have [enabled BuildKit](../../build/buildkit/index.md#getting-started)
|
||||
on your machine.
|
||||
|
||||
|
||||
## Overview
|
||||
|
||||
Now that we have a good overview of containers and the Docker platform, let’s
|
||||
take a look at building our first image. An image includes everything you need
|
||||
to run an application – the code or binary, runtime, dependencies, and any other
|
||||
file system objects required.
|
||||
In this section we are going to build a container image. The image includes everything you need
|
||||
to run your application – the compiled application binary file, the runtime, the libraries, and
|
||||
all other resources required by your application.
|
||||
|
||||
## Required software
|
||||
|
||||
To complete this tutorial, you need the following:
|
||||
|
||||
- Go version 1.16 or later. You might want to [download and install Go](https://golang.org/dl/) first.
|
||||
- Docker running locally. Follow the instructions to [download and install Docker](../../desktop/index.md).
|
||||
- An IDE or a text editor to edit files. We recommend using [Visual Studio Code](https://code.visualstudio.com/){: target="_blank" rel="noopener" class="_"}.
|
||||
- Go version 1.19 or later. Visit the [download page for Go](https://golang.org/dl/){:target="_blank" rel="noopener" class="_"} first and install the toolchain.
|
||||
- Docker running locally. Follow the [instructions to download and install Docker](../../desktop/index.md).
|
||||
- An IDE or a text editor to edit files. [Visual Studio Code](https://code.visualstudio.com/){: target="_blank" rel="noopener" class="_"} is a free and popular choice but you can use anything you feel comfortable with.
|
||||
- A Git client. We'll use a command-line based `git` client throughout this module, but you are free to use whatever works for you.
|
||||
- A command-line terminal application. The examples shown in this module are from the Linux shell, but they should work in PowerShell, Windows Command Prompt, or OS X Terminal with minimal, if any, modifications.
|
||||
|
||||
## Meet the example application
|
||||
|
||||
To avoid losing focus on Docker's features, the sample application is a minimal
|
||||
HTTP server that has only three features:
|
||||
The example application is a *caricature* of a microservice. It is purposefully trivial to keep focus on learning the basics of containerization for Go applications.
|
||||
|
||||
* It responds with a text message containing a heart symbol ("<3") on requests to `/`.
|
||||
* It responds with `{"Status" : "OK"}` JSON to the health check request on requests to `/ping`.
|
||||
* The port it listens on is configurable using the environment variable `HTTP_PORT`. The default value is `8080`.
|
||||
The application offers two HTTP endpoints:
|
||||
|
||||
Thus, it somewhat mimics enough basic properties of a REST microservice to be
|
||||
useful for our learning of Docker.
|
||||
* It responds with a string containing a heart symbol (`<3`) to requests to `/`.
|
||||
* It responds with `{"Status" : "OK"}` JSON to a request to `/health`.
|
||||
|
||||
The source code for the application is in the [github.com/olliefr/docker-gs-ping](https://github.com/olliefr/docker-gs-ping){: target="_blank" rel="noopener" class="_"}
|
||||
GitHub repository. Please feel free to clone or fork it.
|
||||
It responds with HTTP error 404 to any other request.
|
||||
|
||||
For our present study, we clone it to our local machine:
|
||||
The application listens on a TCP port defined by the value of environment variable `PORT`. The default value is `8080`.
|
||||
|
||||
The application is *stateless*.
|
||||
|
||||
The complete source code for the application is on GitHub: [github.com/olliefr/docker-gs-ping](https://github.com/olliefr/docker-gs-ping){: target="_blank" rel="noopener" class="_"}. You are encouraged to fork it and experiment with it as much as you like.
|
||||
|
||||
To continue, we clone the application repository to our local machine:
|
||||
|
||||
```console
|
||||
$ git clone https://github.com/olliefr/docker-gs-ping
|
||||
```
|
||||
|
||||
The application's `main.go` file is fairly straightforward, if you are familiar
|
||||
with Go:
|
||||
The application's `main.go` file is fairly straightforward, if you are familiar with Go:
|
||||
|
||||
{% raw %}
|
||||
```go
|
||||
|
@ -79,17 +72,26 @@ func main() {
|
|||
return c.HTML(http.StatusOK, "Hello, Docker! <3")
|
||||
})
|
||||
|
||||
e.GET("/ping", func(c echo.Context) error {
|
||||
e.GET("/health", func(c echo.Context) error {
|
||||
return c.JSON(http.StatusOK, struct{ Status string }{Status: "OK"})
|
||||
})
|
||||
|
||||
httpPort := os.Getenv("HTTP_PORT")
|
||||
httpPort := os.Getenv("PORT")
|
||||
if httpPort == "" {
|
||||
httpPort = "8080"
|
||||
}
|
||||
|
||||
e.Logger.Fatal(e.Start(":" + httpPort))
|
||||
}
|
||||
|
||||
// Simple implementation of an integer minimum
|
||||
// Adapted from: https://gobyexample.com/testing-and-benchmarking
|
||||
func IntMin(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
```
|
||||
{% endraw %}
|
||||
|
||||
|
@ -110,7 +112,7 @@ the banner, as illustrated in the next figure.
|
|||
____ __
|
||||
/ __/___/ / ___
|
||||
/ _// __/ _ \/ _ \
|
||||
/___/\__/_//_/\___/ v4.2.2
|
||||
/___/\__/_//_/\___/ v4.10.2
|
||||
High performance, minimalist Go web framework
|
||||
https://echo.labstack.com
|
||||
____________________________________O/_______
|
||||
|
@ -118,58 +120,61 @@ ____________________________________O/_______
|
|||
⇨ http server started on [::]:8080
|
||||
```
|
||||
|
||||
Let's run a quick _smoke test_ on the application. **In a new terminal**, run a
|
||||
request using `curl`. Alternatively, you can use your favourite web browser as
|
||||
well.
|
||||
Let's run a quick _smoke test_ by accessing the application on `http://localhost:8080`.
|
||||
You can use your favourite web browser, or even a `curl` command in the terminal:
|
||||
|
||||
```console
|
||||
$ curl http://localhost:8080/
|
||||
Hello, Docker! <3
|
||||
```
|
||||
|
||||
So, the application responds with a greeting, just as the first business
|
||||
requirement says it should. Great.
|
||||
This verifies that the application builds locally and we can start it without an error.
|
||||
That's a milestone to celebrate!
|
||||
|
||||
Having established that the server is running and is accessible, let's proceed
|
||||
to "dockerizing" it.
|
||||
Now we are ready to "containerize" it.
|
||||
|
||||
## Create a Dockerfile for the application
|
||||
|
||||
Next, we need to add a line in our Dockerfile that tells Docker what base image
|
||||
we would like to use for our application.
|
||||
To build a container image with Docker, a *Dockerfile* with build instructions is required.
|
||||
|
||||
We begin our `Dockerfile` with the (optional) parser directive line that instructs BuildKit to
|
||||
interpret our file according to the grammar rules for the specified version of the syntax.
|
||||
|
||||
We then tell Docker what *base image* we would like to use for our application:
|
||||
|
||||
```dockerfile
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
FROM golang:1.16-alpine
|
||||
FROM golang:1.19
|
||||
```
|
||||
|
||||
Docker images can be inherited from other images. Therefore, instead of creating
|
||||
our own base image, we’ll use the official Go image that already has all the tools
|
||||
and packages to compile and run a Go application. You can think of this in the
|
||||
same way you would think about class inheritance in object oriented programming
|
||||
or functional composition in functional programming.
|
||||
|
||||
When we have used that `FROM` command, we told Docker to include in our image all the functionality from the `golang:1.16-alpine` image. All of our consequent commands would build on top of that "base" image.
|
||||
our own base image from scratch, we can use the official Go image that already has
|
||||
all necessary tools and libraries to compile and run a Go application.
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> If you want to learn more about creating your own base images, see [creating base images](../../build/building/base-images.md) section of the guide.
|
||||
> If you are curious about creating your own base images, you can check out the following section of this guide: [creating base images](../../build/building/base-images.md).
|
||||
> Note, however, that this is not necessary to continue with our task at hand.
|
||||
|
||||
Now that we have defined the "base" image for our upcoming container image,
|
||||
we can begin building on top of it.
|
||||
|
||||
To make things easier when running the rest of our commands, let’s create a
|
||||
directory _inside_ the image that we are building. This also instructs Docker
|
||||
to use this directory as the default _destination_ for all subsequent commands.
|
||||
This way we do not have to type out full file paths but can use relative paths
|
||||
based on this directory.
|
||||
This way we do not have to type out full file paths in the `Dockerfile`,
|
||||
the relative paths will be based on this directory.
|
||||
|
||||
```dockerfile
|
||||
WORKDIR /app
|
||||
```
|
||||
|
||||
Usually the very first thing you do once you’ve downloaded a project written in
|
||||
Go is to install the modules necessary to compile it.
|
||||
Go is to install the modules necessary to compile it. Note, that the base image
|
||||
has the toolchain already, but our source code is not in it yet.
|
||||
|
||||
But before we can run `go mod download` inside our image, we need to get our
|
||||
So before we can run `go mod download` inside our image, we need to get our
|
||||
`go.mod` and `go.sum` files copied into it. We use the `COPY` command to do this.
|
||||
|
||||
In its simplest form, the `COPY` command takes two parameters. The first
|
||||
|
@ -177,13 +182,21 @@ parameter tells Docker what files you want to copy into the image. The last
|
|||
parameter tells Docker where you want that file to be copied to.
|
||||
|
||||
We’ll copy the `go.mod` and `go.sum` file into our project directory `/app` which,
|
||||
owing to our use of `WORKDIR`, is the current directory (`.`) inside the image.
|
||||
owing to our use of `WORKDIR`, is the current directory (`./`) inside the image.
|
||||
Unlike some modern shells that appear to be indifferent to the use of trailing slash (`/`),
|
||||
and can figure out what the user meant (most of the time), Docker's `COPY` command
|
||||
is quite sensitive in its interpretation of the trailing slash.
|
||||
|
||||
```dockerfile
|
||||
COPY go.mod ./
|
||||
COPY go.sum ./
|
||||
COPY go.mod go.sum ./
|
||||
```
|
||||
|
||||
> **Notice**
|
||||
>
|
||||
> Please take some time to familiarise yourself with the trailing slash treatment
|
||||
> by the `COPY` command: [Dockerfile reference](../../engine/reference/builder.md/#copy)
|
||||
> as it might otherwise trick you up in more ways than you can imagine.
|
||||
|
||||
Now that we have the module files inside the Docker image that we are building,
|
||||
we can use the `RUN` command to execute the command `go mod download` there as
|
||||
well. This works exactly the same as if we were running `go` locally on our
|
||||
|
@ -194,9 +207,8 @@ inside the image.
|
|||
RUN go mod download
|
||||
```
|
||||
|
||||
At this point, we have an image that is based on Go environment version 1.16
|
||||
(or a later minor version, since we had specified `1.16` as our tag in the
|
||||
`FROM` command) and we have installed our dependencies.
|
||||
At this point, we have a Go toolchain version 1.19.x and all our Go dependencies
|
||||
installed inside the image.
|
||||
|
||||
The next thing we need to do is to copy our source code into the image. We’ll
|
||||
use the `COPY` command just like we did with our module files before.
|
||||
|
@ -213,7 +225,7 @@ Now, we would like to compile our application. To that end, we use the familiar
|
|||
`RUN` command:
|
||||
|
||||
```dockerfile
|
||||
RUN go build -o /docker-gs-ping
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o /docker-gs-ping
|
||||
```
|
||||
|
||||
This should be familiar. The result of that command will be a static application
|
||||
|
@ -237,45 +249,48 @@ Here's the complete `Dockerfile`:
|
|||
```dockerfile
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
FROM golang:1.16-alpine
|
||||
FROM golang:1.19
|
||||
|
||||
# Set destination for COPY
|
||||
WORKDIR /app
|
||||
|
||||
COPY go.mod ./
|
||||
COPY go.sum ./
|
||||
# Download Go modules
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# Copy the source code. Note the slash at the end, as explained in
|
||||
# https://docs.docker.com/engine/reference/builder/#copy
|
||||
COPY *.go ./
|
||||
|
||||
RUN go build -o /docker-gs-ping
|
||||
# Build
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o /docker-gs-ping
|
||||
|
||||
# Optional:
|
||||
# To bind to a TCP port, runtime parameters must be supplied to the docker command.
|
||||
# But we can document in the Dockerfile what ports
|
||||
# the application is going to listen on by default.
|
||||
# https://docs.docker.com/engine/reference/builder/#expose
|
||||
EXPOSE 8080
|
||||
|
||||
# Run
|
||||
CMD [ "/docker-gs-ping" ]
|
||||
```
|
||||
|
||||
The `Dockerfile` may also contain _comments_. They always begin with a `#` symbol,
|
||||
and must be at the beginning of a line. Comments are there for your convenience
|
||||
to allow documenting your `Dockerfile`. Dockerfile _directives_, such as the
|
||||
`syntax` directive we added, must always be at the very top of the `Dockerfile`,
|
||||
so when adding comments, make sure they are after those directives:
|
||||
to allow documenting your `Dockerfile`.
|
||||
|
||||
There is also a concept of Dockerfile _directives_, such as the `syntax` directive we added.
|
||||
The directives must always be at the very top of the `Dockerfile`, so when adding comments,
|
||||
make sure that the comments follow *after* any directives that you may have used:
|
||||
|
||||
```dockerfile
|
||||
# syntax=docker/dockerfile:1
|
||||
# A sample microservice in Go packaged into a container image.
|
||||
|
||||
# Alpine is chosen for its small footprint
|
||||
# compared to Ubuntu
|
||||
FROM golang:1.16-alpine
|
||||
FROM golang:1.19
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Download necessary Go modules
|
||||
COPY go.mod ./
|
||||
COPY go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# ... the rest of the Dockerfile is ...
|
||||
# ... omitted from this example ...
|
||||
# ...
|
||||
```
|
||||
|
||||
## Build the image
|
||||
|
@ -293,32 +308,39 @@ Let's build our first Docker image!
|
|||
|
||||
```console
|
||||
$ docker build --tag docker-gs-ping .
|
||||
```
|
||||
|
||||
[+] Building 3.6s (12/12) FINISHED
|
||||
=> [internal] load build definition from Dockerfile 0.1s
|
||||
=> => transferring dockerfile: 38B 0.0s
|
||||
=> [internal] load .dockerignore 0.1s
|
||||
=> => transferring context: 2B 0.0s
|
||||
=> [internal] load metadata for docker.io/library/golang:1.16-alpine 3.0s
|
||||
=> [1/7] FROM docker.io/library/golang:1.16-alpine@sha256:49c07aa83790aca732250c2258b59 0.0s
|
||||
=> => resolve docker.io/library/golang:1.16-alpine@sha256:49c07aa83790aca732250c2258b59 0.0s
|
||||
=> [internal] load build context 0.1s
|
||||
=> => transferring context: 114B 0.0s
|
||||
=> CACHED [2/7] WORKDIR /app 0.0s
|
||||
=> CACHED [3/7] COPY go.mod . 0.0s
|
||||
=> CACHED [4/7] COPY go.sum . 0.0s
|
||||
=> CACHED [5/7] RUN go mod download 0.0s
|
||||
=> CACHED [6/7] COPY *.go . 0.0s
|
||||
=> CACHED [7/7] RUN go build -o /docker-gs-ping 0.0s
|
||||
=> exporting to image 0.1s
|
||||
=> => exporting layers 0.0s
|
||||
=> => writing image sha256:336a3f164d0f079f2e42cd1d38f24ab9110d47d481f1db7f2a0b0d2859ec 0.0s
|
||||
=> => naming to docker.io/library/docker-gs-ping 0.0s
|
||||
The build process will print some diagnostic messages as it goes through the build steps.
|
||||
The following is just an example of what these messages may look like.
|
||||
|
||||
```console
|
||||
[+] Building 2.2s (15/15) FINISHED
|
||||
=> [internal] load build definition from Dockerfile 0.0s
|
||||
=> => transferring dockerfile: 701B 0.0s
|
||||
=> [internal] load .dockerignore 0.0s
|
||||
=> => transferring context: 2B 0.0s
|
||||
=> resolve image config for docker.io/docker/dockerfile:1 1.1s
|
||||
=> CACHED docker-image://docker.io/docker/dockerfile:1@sha256:39b85bbfa7536a5feceb7372a0817649ecb2724562a38360f4d6a7782a409b14 0.0s
|
||||
=> [internal] load build definition from Dockerfile 0.0s
|
||||
=> [internal] load .dockerignore 0.0s
|
||||
=> [internal] load metadata for docker.io/library/golang:1.19 0.7s
|
||||
=> [1/6] FROM docker.io/library/golang:1.19@sha256:5d947843dde82ba1df5ac1b2ebb70b203d106f0423bf5183df3dc96f6bc5a705 0.0s
|
||||
=> [internal] load build context 0.0s
|
||||
=> => transferring context: 6.08kB 0.0s
|
||||
=> CACHED [2/6] WORKDIR /app 0.0s
|
||||
=> CACHED [3/6] COPY go.mod go.sum ./ 0.0s
|
||||
=> CACHED [4/6] RUN go mod download 0.0s
|
||||
=> CACHED [5/6] COPY *.go ./ 0.0s
|
||||
=> CACHED [6/6] RUN CGO_ENABLED=0 GOOS=linux go build -o /docker-gs-ping 0.0s
|
||||
=> exporting to image 0.0s
|
||||
=> => exporting layers 0.0s
|
||||
=> => writing image sha256:ede8ff889a0d9bc33f7a8da0673763c887a258eb53837dd52445cdca7b7df7e3 0.0s
|
||||
=> => naming to docker.io/library/docker-gs-ping 0.0s
|
||||
```
|
||||
|
||||
Your exact output will vary, but provided there aren't any errors, you should
|
||||
see the `FINISHED` line in the build output. This means Docker has successfully
|
||||
built our image and assigned a `docker-gs-ping` tag to it.
|
||||
see the word `FINISHED` in the first line of output. This means Docker has successfully
|
||||
built our image named `docker-gs-ping`.
|
||||
|
||||
## View local images
|
||||
|
||||
|
@ -332,13 +354,14 @@ To list images, run the `docker image ls`command (or the `docker images` shortha
|
|||
```console
|
||||
$ docker image ls
|
||||
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
docker-gs-ping latest 336a3f164d0f 39 minutes ago 540MB
|
||||
postgres 13.2 c5ec7353d87d 7 weeks ago 314MB
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
docker-gs-ping latest 7f153fbcc0a8 2 minutes ago 1.11GB
|
||||
...
|
||||
```
|
||||
|
||||
Your exact output may vary, but you should see `docker-gs-ping` image with the
|
||||
`latest` tag.
|
||||
Your exact output may vary, but you should see the `docker-gs-ping` image with the
|
||||
`latest` tag. Because we had not specified a custom tag when we built our image,
|
||||
Docker assumed that the tag would be `latest`, which is a special value.
|
||||
|
||||
## Tag images
|
||||
|
||||
|
@ -372,10 +395,10 @@ images:
|
|||
```console
|
||||
$ docker image ls
|
||||
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
docker-gs-ping latest 336a3f164d0f 43 minutes ago 540MB
|
||||
docker-gs-ping v1.0 336a3f164d0f 43 minutes ago 540MB
|
||||
postgres 13.2 c5ec7353d87d 7 weeks ago 314MB
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
docker-gs-ping latest 7f153fbcc0a8 6 minutes ago 1.11GB
|
||||
docker-gs-ping v1.0 7f153fbcc0a8 6 minutes ago 1.11GB
|
||||
...
|
||||
```
|
||||
|
||||
You can see that we have two images that start with `docker-gs-ping`. We know
|
||||
|
@ -392,14 +415,20 @@ $ docker image rm docker-gs-ping:v1.0
|
|||
Untagged: docker-gs-ping:v1.0
|
||||
```
|
||||
|
||||
Notice that the response from Docker tells us that the image has not been removed but only "untagged". Verify this by running the images command:
|
||||
Notice that the response from Docker tells us that the image has not been removed but only "untagged".
|
||||
|
||||
Verify this by running the following command:
|
||||
|
||||
```console
|
||||
$ docker image ls
|
||||
```
|
||||
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
docker-gs-ping latest 336a3f164d0f 45 minutes ago 540MB
|
||||
postgres 13.2 c5ec7353d87d 7 weeks ago 314MB
|
||||
You will see that the tag `v1.0` is no longer in the list of images kept by your Docker instance.
|
||||
|
||||
```
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
docker-gs-ping latest 7f153fbcc0a8 7 minutes ago 1.11GB
|
||||
...
|
||||
```
|
||||
|
||||
The tag `v1.0` has been removed but we still have the `docker-gs-ping:latest`
|
||||
|
@ -407,17 +436,22 @@ tag available on our machine, so the image is there.
|
|||
|
||||
## Multi-stage builds
|
||||
|
||||
You may have noticed that our `docker-gs-ping` image stands at 540MB, which you
|
||||
may think is a lot. You may also be wondering whether our dockerized application
|
||||
still needs the full suite of Go tools, including the compiler, after the
|
||||
application binary had been compiled.
|
||||
You may have noticed that our `docker-gs-ping` image weighs in at over a gigabyte (!!!),
|
||||
which is *a lot* for a tiny compiled Go application. You may also be wondering what happened
|
||||
to the full suite of Go tools, including the compiler, after we had built our image.
|
||||
|
||||
These are legit concerns. Both can be solved by using _multi-stage builds_. The
|
||||
following example is provided with little explanation because this would derail
|
||||
us from our current concerns, but please feel free to explore on your own later.
|
||||
The main idea is that we use one image to produce some artifacts, which are then
|
||||
placed into another, much smaller image, containing only the parts necessary for
|
||||
running the artifacts that we'd built.
|
||||
The answer is that the full toolchain is still there, in the container image.
|
||||
Not only this is inconvenient because of the large file size, but it may also
|
||||
present a security risk when the container is deployed.
|
||||
|
||||
These two issues can be solved by using [multi-stage builds](../../build/building/multi-stage.md).
|
||||
|
||||
In a nutshell, a multi-stage build can carry over the artifacts from one build stage into another,
|
||||
and every build stage can be instantiated from a different base image.
|
||||
|
||||
Thus, in the following example, we are going to use a full-scale official Go image to build
|
||||
our application but then we'll copy the application binary into another image whose base
|
||||
is very lean and does not include the Go toolchain or other optional components.
|
||||
|
||||
The `Dockerfile.multistage` in the sample application's repo has the following
|
||||
content:
|
||||
|
@ -426,25 +460,28 @@ content:
|
|||
```dockerfile
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
## Build
|
||||
FROM golang:1.16-buster AS build
|
||||
# Build the application from source
|
||||
FROM golang:1.19 AS build-stage
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY go.mod ./
|
||||
COPY go.sum ./
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
COPY *.go ./
|
||||
|
||||
RUN go build -o /docker-gs-ping
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o /docker-gs-ping
|
||||
|
||||
## Deploy
|
||||
FROM gcr.io/distroless/base-debian10
|
||||
# Run the tests in the container
|
||||
FROM build-stage AS run-test-stage
|
||||
RUN go test -v ./...
|
||||
|
||||
# Deploy the application binary into a lean image
|
||||
FROM gcr.io/distroless/base-debian11 AS build-release-stage
|
||||
|
||||
WORKDIR /
|
||||
|
||||
COPY --from=build /docker-gs-ping /docker-gs-ping
|
||||
COPY --from=build-stage /docker-gs-ping /docker-gs-ping
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
|
@ -454,42 +491,36 @@ ENTRYPOINT ["/docker-gs-ping"]
|
|||
```
|
||||
{% endraw %}
|
||||
|
||||
Since we have two dockerfiles now, we have to tell Docker that we want to build
|
||||
using our new Dockerfile. We also tag the new image with `multistage` but this
|
||||
word has no special meaning, we only do so that we could compare this new image
|
||||
to the one we've built previously, that is the one we tagged with `latest`:
|
||||
Since we have two Dockerfiles now, we have to tell Docker what Dockerfile we'd like to use
|
||||
to build the image. Let's tag the new image with `multistage`. This tag (like any other,
|
||||
apart from `latest`) has no special meaning for Docker, it's just something we chose.
|
||||
|
||||
```console
|
||||
$ docker build -t docker-gs-ping:multistage -f Dockerfile.multistage .
|
||||
```
|
||||
|
||||
Comparing the sizes of `docker-gs-ping:multistage` and `docker-gs-ping:latest`
|
||||
we see an order-of-magnitude difference!
|
||||
|
||||
```console
|
||||
$ docker image ls
|
||||
we see a *few orders-of-magnitude* difference! (`docker image ls`)
|
||||
|
||||
```
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
docker-gs-ping multistage e3fdde09f172 About a minute ago 27.1MB
|
||||
docker-gs-ping latest 336a3f164d0f About an hour ago 540MB
|
||||
docker-gs-ping multistage e3fdde09f172 About a minute ago 28.1MB
|
||||
docker-gs-ping latest 336a3f164d0f About an hour ago 1.11GB
|
||||
```
|
||||
|
||||
This is due to the fact that the ["distroless" base image](https://github.com/GoogleContainerTools/distroless){:target="_blank" rel="noopener" class="_"}
|
||||
that we have used to deploy our Go application is very barebones and is meant
|
||||
for lean deployments of static binaries.
|
||||
This is so because the ["distroless"](https://github.com/GoogleContainerTools/distroless){:target="_blank" rel="noopener" class="_"}
|
||||
base image that we have used in the second stage of the build is very barebones and is designed for lean deployments of static binaries.
|
||||
|
||||
For more information on multi-stage builds, please feel free to check out
|
||||
[other parts](../../build/building/multi-stage.md) of the Docker
|
||||
documentation. This is, however, not essential for our progress here, so we'll
|
||||
There's much more to multi-stage builds, including the possibility of multi-architecture builds,
|
||||
so please feel free to check out the [multi-stage builds](../../build/building/multi-stage.md)
|
||||
section of Docker documentation. This is, however, not essential for our progress here, so we'll
|
||||
leave it at that.
|
||||
|
||||
## Next steps
|
||||
|
||||
In this module, we took a look at setting up our example Go application that we
|
||||
will use for much of the rest of the tutorial. We also created a `Dockerfile`
|
||||
that we used to build our Docker image. Then, we took a look at tagging our
|
||||
images and removing images and tags. In the next module, we’ll take a look at
|
||||
how to:
|
||||
In this module, we met our example application and built and container image for it.
|
||||
|
||||
In the next module, we’ll take a look at how to:
|
||||
|
||||
[Run your image as a container](run-containers.md){: .button .outline-btn}
|
||||
|
||||
|
|
|
@ -6,25 +6,41 @@ toc_min: 1
|
|||
toc_max: 2
|
||||
---
|
||||
|
||||
In this guide, you will learn how to create a containerized Go application using Docker.
|
||||
|
||||
Why [Go](https://golang.org/){:target="_blank" rel="noopener" class="_"}? Go is an open-source programming language that lets you build simple, reliable, and efficient software. Go is undeniably a major player in the modern Cloud ecosystem; both Docker and Kubernetes are written in Go.
|
||||
|
||||
[golang]: https://golang.org/
|
||||
This guide will show you how to create, test, and deploy containerized Go applications using Docker.
|
||||
|
||||
> **Acknowledgment**
|
||||
>
|
||||
> We'd like to thank [Oliver Frolovs](https://twitter.com/nocturnalgopher){:target="_blank" rel="noopener" class="_"} for his contribution to the Golang get started guide.
|
||||
> We'd like to thank [Oliver Frolovs](https://www.linkedin.com/in/ofr/){:target="_blank" rel="noopener" class="_"} for his contribution to this guide.
|
||||
|
||||
## What will you learn?
|
||||
|
||||
In this guide, you’ll learn how to:
|
||||
|
||||
* Create a new `Dockerfile` which contains instructions required to build a Docker image for a simple Go program
|
||||
* Run the newly built image as a container
|
||||
* Set up a local development environment to connect a database to the container
|
||||
* Use Docker Compose to run your Go application and other services it requires
|
||||
* Create a *Dockerfile* which contains the instructions for building a container image for a program written in Go.
|
||||
* Run the image as a container in your local Docker instance and manage the container's lifecycle.
|
||||
* Use multi-stage builds for building small images efficiently while keeping your *Dockerfiles* easy to read and maintain.
|
||||
* Use Docker Compose to orchestrate running of multiple related containers together in a development environment.
|
||||
* Configure a CI/CD pipeline for your application using [GitHub Actions](https://docs.github.com/en/actions){:target="_blank" rel="noopener" class="_"}
|
||||
* Deploy your containerized Go application to Google [Cloud Run](https://cloud.google.com/run/docs/overview/what-is-cloud-run){:target="_blank" rel="noopener" class="_"} serverless platform.
|
||||
|
||||
You can containerize your own Go application using the examples and resources provided after you complete the Go getting started modules.
|
||||
## Prerequisites
|
||||
|
||||
Some basic understanding of Go and its toolchain is assumed. This is not a Go tutorial. If you are new to the language,
|
||||
the [Go website](https://golang.org/){: target="_blank" rel="noopener" class="_"} is a great place to explore,
|
||||
so *go* (pun intended) check it out!
|
||||
|
||||
You also must know some basic [Docker concepts](../../get-started/overview.md) as well as to
|
||||
be at least vaguely familiar with the [Dockerfile format](../../build/building/packaging.md#dockerfile).
|
||||
|
||||
Your Docker set-up must have BuildKit enabled. BuildKit is enabled by default for all users on [Docker Desktop](../../desktop/index.md).
|
||||
If you have installed Docker Desktop, you don’t have to manually enable BuildKit. If you are running Docker on Linux,
|
||||
please check out BuildKit [getting started](../../build/buildkit/index.md#getting-started) page.
|
||||
|
||||
Some familiarity with the command line is also expected.
|
||||
|
||||
## What's next?
|
||||
|
||||
The aim of this guide is to provide enough examples and instructions for you to containerize your own Go application and deploy it into the Cloud.
|
||||
|
||||
Let's get started!
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ $ docker run docker-gs-ping
|
|||
____ __
|
||||
/ __/___/ / ___
|
||||
/ _// __/ _ \/ _ \
|
||||
/___/\__/_//_/\___/ v4.2.2
|
||||
/___/\__/_//_/\___/ v4.10.2
|
||||
High performance, minimalist Go web framework
|
||||
https://echo.labstack.com
|
||||
____________________________________O/_______
|
||||
|
|
Loading…
Reference in New Issue