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:
Oliver Frolovs 2023-04-05 19:28:56 +01:00 committed by GitHub
parent d04fccbcd4
commit 25738b74b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 213 additions and 166 deletions

View File

@ -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, lets
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, well 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, lets 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 youve 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.
Well 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. Well
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, well 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, well take a look at how to:
[Run your image as a container](run-containers.md){: .button .outline-btn}

View File

@ -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, youll 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 dont 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!

View File

@ -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/_______