mirror of https://github.com/docker/docs.git
freshness: java and go language-specific guides (#18466)
* refresh go and java language guides Signed-off-by: Craig Osterhout <craig.osterhout@docker.com>
This commit is contained in:
parent
ae798c90b1
commit
59990dde0f
|
@ -10,22 +10,22 @@ This guide will show you how to create, test, and deploy containerized Go applic
|
|||
|
||||
> **Acknowledgment**
|
||||
>
|
||||
> We'd like to thank [Oliver Frolovs](https://www.linkedin.com/in/ofr/) for his contribution to this guide.
|
||||
> Docker would like to thank [Oliver Frolovs](https://www.linkedin.com/in/ofr/) for his contribution to this guide.
|
||||
|
||||
## What will you learn?
|
||||
|
||||
In this guide, you’ll learn how to:
|
||||
|
||||
* Create a *Dockerfile* which contains the instructions for building a container image for a program written in Go.
|
||||
* 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 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)
|
||||
* Deploy your containerized Go application to Google [Cloud Run](https://cloud.google.com/run/docs/overview/what-is-cloud-run) serverless platform.
|
||||
* Deploy your containerized Go application.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Some basic understanding of Go and its toolchain is assumed. This is not a Go tutorial. If you are new to the language,
|
||||
Some basic understanding of Go and its toolchain is assumed. This isn't a Go tutorial. If you are new to the language,
|
||||
the [Go website](https://golang.org/) is a great place to explore,
|
||||
so *go* (pun intended) check it out!
|
||||
|
||||
|
@ -42,6 +42,6 @@ Some familiarity with the command line is also expected.
|
|||
|
||||
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!
|
||||
Start by building your first Go image.
|
||||
|
||||
{{< button text="Build your Go image" url="build-images.md" >}}
|
|
@ -8,9 +8,10 @@ aliases:
|
|||
|
||||
## Overview
|
||||
|
||||
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.
|
||||
In this section you're 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
|
||||
|
||||
|
@ -19,12 +20,12 @@ To complete this tutorial, you need the following:
|
|||
- Go version 1.19 or later. Visit the [download page for Go](https://golang.org/dl/) 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/) 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 Git client. This guide uses a command-line based `git` client, 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
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
The application offers two HTTP endpoints:
|
||||
|
||||
|
@ -35,17 +36,17 @@ It responds with HTTP error 404 to any other request.
|
|||
|
||||
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 application is stateless.
|
||||
|
||||
The complete source code for the application is on GitHub: [github.com/docker/docker-gs-ping](https://github.com/docker/docker-gs-ping). 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:
|
||||
To continue, clone the application repository to your local machine:
|
||||
|
||||
```console
|
||||
$ git clone https://github.com/docker/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 straightforward, if you are familiar with Go:
|
||||
|
||||
|
||||
```go
|
||||
|
@ -92,19 +93,18 @@ func IntMin(a, b int) int {
|
|||
}
|
||||
```
|
||||
|
||||
|
||||
## Smoke test the application
|
||||
|
||||
Let’s start our application and make sure it’s running properly. Open your
|
||||
terminal and navigate to the directory into which you cloned the project's repo.
|
||||
From now on, we'll refer to this directory as the **project directory**.
|
||||
Start your application and make sure it’s running. Open your
|
||||
terminal and navigate to the directory into which you cloned the project's repository.
|
||||
From now on, this guide will refer to this directory as the **project directory**.
|
||||
|
||||
```console
|
||||
$ go run main.go
|
||||
```
|
||||
|
||||
This should compile and start the server as a foreground application, outputting
|
||||
the banner, as illustrated in the next figure.
|
||||
the banner, as illustrated in the following figure.
|
||||
|
||||
```
|
||||
____ __
|
||||
|
@ -118,7 +118,7 @@ ____________________________________O/_______
|
|||
⇨ http server started on [::]:8080
|
||||
```
|
||||
|
||||
Let's run a quick _smoke test_ by accessing the application on `http://localhost:8080`.
|
||||
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
|
||||
|
@ -126,19 +126,19 @@ $ curl http://localhost:8080/
|
|||
Hello, Docker! <3
|
||||
```
|
||||
|
||||
This verifies that the application builds locally and we can start it without an error.
|
||||
This verifies that the application builds locally and you can start it without an error.
|
||||
That's a milestone to celebrate!
|
||||
|
||||
Now we are ready to "containerize" it.
|
||||
Now you're ready to containerize it.
|
||||
|
||||
## Create a Dockerfile for the application
|
||||
|
||||
To build a container image with Docker, a *Dockerfile* with build instructions is required.
|
||||
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.
|
||||
Begin your `Dockerfile` with the (optional) parser directive line that instructs BuildKit to
|
||||
interpret your 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:
|
||||
You then tell Docker what base image you would like to use for your application:
|
||||
|
||||
```dockerfile
|
||||
# syntax=docker/dockerfile:1
|
||||
|
@ -147,69 +147,71 @@ FROM golang:1.19
|
|||
```
|
||||
|
||||
Docker images can be inherited from other images. Therefore, instead of creating
|
||||
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.
|
||||
your own base image from scratch, you can use the official Go image that already
|
||||
has all necessary tools and libraries to compile and run a Go application.
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> 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.
|
||||
> Note, however, that this isn't necessary to continue with your task at hand.
|
||||
|
||||
Now that we have defined the "base" image for our upcoming container image,
|
||||
we can begin building on top of it.
|
||||
Now that you have defined the base image for your upcoming container image, you
|
||||
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 in the `Dockerfile`,
|
||||
the relative paths will be based on this directory.
|
||||
To make things easier when running the rest of your commands, create a directory
|
||||
inside the image that you're building. This also instructs Docker to use this
|
||||
directory as the default destination for all subsequent commands. This way you
|
||||
don't 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. Note, that the base image
|
||||
has the toolchain already, but our source code is not in it yet.
|
||||
Go is to install the modules necessary to compile it. Note, that the base image
|
||||
has the toolchain already, but your source code isn't in it yet.
|
||||
|
||||
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.
|
||||
So before you can run `go mod download` inside your image, you need to get your
|
||||
`go.mod` and `go.sum` files copied into it. Use the `COPY` command to do this.
|
||||
|
||||
In its simplest form, the `COPY` command takes two parameters. The first
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
Copy the `go.mod` and `go.sum` file into your project directory `/app` which,
|
||||
owing to your 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 go.sum ./
|
||||
```
|
||||
|
||||
> **Notice**
|
||||
> **Note**
|
||||
>
|
||||
> 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.
|
||||
> If you'd like to familiarize yourself with the trailing slash treatment by the
|
||||
> `COPY` command, see [Dockerfile
|
||||
> reference](../../engine/reference/builder.md/#copy). This trailing slash can
|
||||
> cause issues 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
|
||||
machine, but this time these Go modules will be installed into a directory
|
||||
inside the image.
|
||||
Now that you have the module files inside the Docker image that you are
|
||||
building, you can use the `RUN` command to run the command `go mod download`
|
||||
there as well. This works exactly the same as if you were running `go` locally
|
||||
on your machine, but this time these Go modules will be installed into a
|
||||
directory inside the image.
|
||||
|
||||
```dockerfile
|
||||
RUN go mod download
|
||||
```
|
||||
|
||||
At this point, we have a Go toolchain version 1.19.x and all our Go dependencies
|
||||
installed inside the image.
|
||||
At this point, you have a Go toolchain version 1.19.x and all your 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.
|
||||
The next thing you need to do is to copy your source code into the image. You’ll
|
||||
use the `COPY` command just like you did with your module files before.
|
||||
|
||||
```dockerfile
|
||||
COPY *.go ./
|
||||
|
@ -219,8 +221,7 @@ This `COPY` command uses a wildcard to copy all files with `.go` extension
|
|||
located in the current directory on the host (the directory where the `Dockerfile`
|
||||
is located) into the current directory inside the image.
|
||||
|
||||
Now, we would like to compile our application. To that end, we use the familiar
|
||||
`RUN` command:
|
||||
Now, to compile your application, use the familiar `RUN` command:
|
||||
|
||||
```dockerfile
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o /docker-gs-ping
|
||||
|
@ -228,15 +229,15 @@ 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
|
||||
binary named `docker-gs-ping` and located in the root of the filesystem of the
|
||||
image that we are building. We could have put the binary into any other place we
|
||||
desire inside that image, the root directory has no special meaning in this
|
||||
image that you are building. You could have put the binary into any other place
|
||||
you desire inside that image, the root directory has no special meaning in this
|
||||
regard. It's just convenient to use it to keep the file paths short for improved
|
||||
readability.
|
||||
|
||||
Now, all that is left to do is to tell Docker what command to execute when our
|
||||
image is used to start a container.
|
||||
Now, all that is left to do is to tell Docker what command to run when your
|
||||
image is used to start a container.
|
||||
|
||||
We do this with the `CMD` command:
|
||||
You do this with the `CMD` command:
|
||||
|
||||
```dockerfile
|
||||
CMD ["/docker-gs-ping"]
|
||||
|
@ -274,13 +275,14 @@ EXPOSE 8080
|
|||
CMD ["/docker-gs-ping"]
|
||||
```
|
||||
|
||||
The `Dockerfile` may also contain _comments_. They always begin with a `#` symbol,
|
||||
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`.
|
||||
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:
|
||||
There is also a concept of Dockerfile directives, such as the `syntax` directive
|
||||
you 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
|
||||
|
@ -293,16 +295,16 @@ FROM golang:1.19
|
|||
|
||||
## Build the image
|
||||
|
||||
Now that we've created our `Dockerfile`, let’s build an image from it. The
|
||||
`docker build` command creates Docker images from the `Dockerfile` and a "context".
|
||||
A build _context_ is the set of files located in the specified path or URL. The
|
||||
Now that you've created our `Dockerfile`, build an image from it. The `docker
|
||||
build` command creates Docker images from the `Dockerfile` and a context. A
|
||||
build context is the set of files located in the specified path or URL. The
|
||||
Docker build process can access any of the files located in the context.
|
||||
|
||||
The build command optionally takes a `--tag` flag. This flag is used to label
|
||||
the image with a string value, which is easy for humans to read and recognise.
|
||||
If you do not pass a `--tag`, Docker will use `latest` as the default value.
|
||||
If you don't pass a `--tag`, Docker will use `latest` as the default value.
|
||||
|
||||
Let's build our first Docker image!
|
||||
Build your first Docker image.
|
||||
|
||||
```console
|
||||
$ docker build --tag docker-gs-ping .
|
||||
|
@ -337,15 +339,15 @@ The following is just an example of what these messages may look like.
|
|||
```
|
||||
|
||||
Your exact output will vary, but provided there aren't any errors, you should
|
||||
see the word `FINISHED` in the first line of output. This means Docker has successfully
|
||||
built our image named `docker-gs-ping`.
|
||||
see the word `FINISHED` in the first line of output. This means Docker has
|
||||
successfully built your image named `docker-gs-ping`.
|
||||
|
||||
## View local images
|
||||
|
||||
To see the list of images we have on our local machine, we have two options. One
|
||||
is to use the CLI and the other is to use [Docker Desktop](../../desktop/index.md).
|
||||
Since we are currently working in the terminal, let’s take a look at listing
|
||||
images with the CLI.
|
||||
To see the list of images you have on your local machine, you have two options.
|
||||
One is to use the CLI and the other is to use [Docker
|
||||
Desktop](../../desktop/index.md). Since you're currently working in the
|
||||
terminal, take a look at listing images with the CLI.
|
||||
|
||||
To list images, run the `docker image ls`command (or the `docker images` shorthand):
|
||||
|
||||
|
@ -357,33 +359,33 @@ docker-gs-ping latest 7f153fbcc0a8 2 minutes ago 1.11GB
|
|||
...
|
||||
```
|
||||
|
||||
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.
|
||||
Your exact output may vary, but you should see the `docker-gs-ping` image with
|
||||
the `latest` tag. Because you didn't specify a custom tag when you built your
|
||||
image, Docker assumed that the tag would be `latest`, which is a special value.
|
||||
|
||||
## Tag images
|
||||
|
||||
An image name is made up of slash-separated name components. Name components may
|
||||
contain lowercase letters, digits and separators. A separator is defined as a
|
||||
contain lowercase letters, digits, and separators. A separator is defined as a
|
||||
period, one or two underscores, or one or more dashes. A name component may not
|
||||
start or end with a separator.
|
||||
|
||||
An image is made up of a manifest and a list of layers. In simple terms, a “tag”
|
||||
An image is made up of a manifest and a list of layers. In simple terms, a tag
|
||||
points to a combination of these artifacts. You can have multiple tags for the
|
||||
image and, in fact, most images have multiple tags. Let’s create a second tag
|
||||
for the image we had built and take a look at its layers.
|
||||
image and, in fact, most images have multiple tags. Create a second tag
|
||||
for the image you built and take a look at its layers.
|
||||
|
||||
Use the `docker image tag` (or `docker tag` shorthand) command to create a new
|
||||
tag for our image. This command takes two arguments; the first argument is the
|
||||
"source" image, and the second is the new tag to create. The following command
|
||||
creates a new `docker-gs-ping:v1.0` tag for the `docker-gs-ping:latest` we built
|
||||
above:
|
||||
tag for your image. This command takes two arguments; the first argument is the
|
||||
source image, and the second is the new tag to create. The following command
|
||||
creates a new `docker-gs-ping:v1.0` tag for the `docker-gs-ping:latest` you
|
||||
built:
|
||||
|
||||
```console
|
||||
$ docker image tag docker-gs-ping:latest docker-gs-ping:v1.0
|
||||
```
|
||||
|
||||
The Docker `tag` command creates a new tag for the image. It does not create a
|
||||
The Docker `tag` command creates a new tag for the image. It doesn't create a
|
||||
new image. The tag points to the same image and is just another way to reference
|
||||
the image.
|
||||
|
||||
|
@ -399,12 +401,12 @@ 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
|
||||
they are the same image because if you look at the `IMAGE ID` column, you can
|
||||
You can see that you have two images that start with `docker-gs-ping`. You know
|
||||
they're the same image because if you look at the `IMAGE ID` column, you can
|
||||
see that the values are the same for the two images. This value is a unique
|
||||
identifier Docker uses internally to identify the image.
|
||||
|
||||
Let’s remove the tag that we had just created. To do this, we’ll use the
|
||||
Remove the tag that you just created. To do this, you’ll use the
|
||||
`docker image rm` command, or the shorthand `docker rmi` (which stands for
|
||||
"remove image"):
|
||||
|
||||
|
@ -413,7 +415,8 @@ $ 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".
|
||||
Notice that the response from Docker tells you that the image hasn't been
|
||||
removed but only untagged.
|
||||
|
||||
Verify this by running the following command:
|
||||
|
||||
|
@ -429,14 +432,15 @@ 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`
|
||||
tag available on our machine, so the image is there.
|
||||
The tag `v1.0` has been removed but you still have the `docker-gs-ping:latest`
|
||||
tag available on your machine, so the image is there.
|
||||
|
||||
## Multi-stage builds
|
||||
|
||||
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.
|
||||
You may have noticed that your `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 you had built your image.
|
||||
|
||||
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
|
||||
|
@ -447,12 +451,13 @@ These two issues can be solved by using [multi-stage builds](../../build/buildin
|
|||
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.
|
||||
Thus, in the following example, you are going to use a full-scale official Go
|
||||
image to build your application. Then you'll copy the application binary into
|
||||
another image whose base is very lean and doesn't include the Go toolchain or
|
||||
other optional components.
|
||||
|
||||
The `Dockerfile.multistage` in the sample application's repo has the following
|
||||
content:
|
||||
The `Dockerfile.multistage` in the sample application's repository has the
|
||||
following content:
|
||||
|
||||
|
||||
```dockerfile
|
||||
|
@ -489,42 +494,36 @@ ENTRYPOINT ["/docker-gs-ping"]
|
|||
```
|
||||
|
||||
|
||||
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.
|
||||
Since you have two Dockerfiles now, you have to tell Docker what Dockerfile
|
||||
you'd like to use to build the image. Tag the new image with `multistage`. This
|
||||
tag (like any other, apart from `latest`) has no special meaning for Docker,
|
||||
it's just something you 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 a *few orders-of-magnitude* difference! (`docker image ls`)
|
||||
you 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 28.1MB
|
||||
docker-gs-ping latest 336a3f164d0f About an hour ago 1.11GB
|
||||
```
|
||||
|
||||
This is so because the ["distroless"](https://github.com/GoogleContainerTools/distroless)
|
||||
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.
|
||||
base image that you have used in the second stage of the build is very barebones and is designed for lean deployments of static binaries.
|
||||
|
||||
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.
|
||||
so feel free to check out [multi-stage builds](../../build/building/multi-stage.md). This is, however, not essential for your progress here.
|
||||
|
||||
## Next steps
|
||||
|
||||
In this module, we met our example application and built and container image for it.
|
||||
In this module, you met your example application and built and container image
|
||||
for it.
|
||||
|
||||
In the next module, we’ll take a look at how to:
|
||||
In the next module, you’ll take a look at how to run your image as a container.
|
||||
|
||||
{{< button text="Run your image as a container" url="run-containers.md" >}}
|
||||
|
||||
## Feedback
|
||||
|
||||
Help us improve this topic by providing your feedback. Let us know what you
|
||||
think by creating an issue in the [Docker Docs]({{% param "repo" %}}/issues/new?title=[Golang%20docs%20feedback])
|
||||
GitHub repository. Alternatively, [create a PR]({{% param "repo" %}}/pulls)
|
||||
to suggest updates.
|
||||
{{< button text="Run your image as a container" url="run-containers.md" >}}
|
|
@ -13,14 +13,10 @@ aliases:
|
|||
|
||||
## Next steps
|
||||
|
||||
In this module, you have learnt how to set up GitHub Actions workflow to an existing dockerized Go project, optimize your workflow to improve build times and reduce the number of pull requests, and finally, we learnt how to push only specific versions to Docker Hub.
|
||||
In this module, you have learned how to set up GitHub Actions workflow to an existing dockerized Go project, optimize your workflow to improve build times, and reduce the number of pull requests. Finally, you learned how to push only specific versions to Docker Hub.
|
||||
|
||||
You can also consider deploying your application to a public Cloud provider, such as Azure and AWS or to an orchestration platform such as Kubernetes.
|
||||
|
||||
In the next module, we’ll look into some options for doing so:
|
||||
In the next module, you’ll look into some options for doing so.
|
||||
|
||||
{{< button text="Deploy your app" url="deploy.md" >}}
|
||||
|
||||
## Feedback
|
||||
|
||||
Help us improve this topic by providing your feedback. Let us know what you think by creating an issue in the [Docker Docs]({{% param "repo" %}}/issues/new?title=[Golang%20docs%20feedback]) GitHub repository. Alternatively, [create a PR]({{% param "repo" %}}/pulls) to suggest updates.
|
||||
|
|
|
@ -4,8 +4,4 @@ keywords: deploy, ACI, ECS, local, development, Go, Golang, cloud, deployment
|
|||
description: Learn how to deploy your application
|
||||
---
|
||||
|
||||
{{< include "deploy.md" >}}
|
||||
|
||||
## Feedback
|
||||
|
||||
Help us improve this topic by providing your feedback. Let us know what you think by creating an issue in the [Docker Docs]({{% param "repo" %}}/issues/new?title=[Golang%20docs%20feedback]) GitHub repository. Alternatively, [create a PR]({{% param "repo" %}}/pulls) to suggest updates.
|
||||
{{< include "deploy.md" >}}
|
|
@ -12,21 +12,21 @@ Work through the steps of the [run your image as a container](run-containers.md)
|
|||
|
||||
## Introduction
|
||||
|
||||
In this module, we'll take a look at running a database engine in a container and connecting it to the extended version of the example application. We are going to see some options for keeping persistent data and for wiring up the containers to talk to one another. Finally, we'll learn how to use Docker Compose to manage such multi-container local development environments effectively.
|
||||
In this module, you'll take a look at running a database engine in a container and connecting it to the extended version of the example application. You are going to see some options for keeping persistent data and for wiring up the containers to talk to one another. Finally, you'll learn how to use Docker Compose to manage such multi-container local development environments effectively.
|
||||
|
||||
## Local database and containers
|
||||
|
||||
The database engine we are going to use is called [CockroachDB](https://www.cockroachlabs.com/product/). It is a modern, Cloud-native, distributed SQL database.
|
||||
The database engine you are going to use is called [CockroachDB](https://www.cockroachlabs.com/product/). It is a modern, Cloud-native, distributed SQL database.
|
||||
|
||||
Instead of compiling CockroachDB from the source code or using the operating system's native package manager to install CockroachDB, we are going to use the [Docker image for CockroachDB](https://hub.docker.com/r/cockroachdb/cockroach) and run it in a container.
|
||||
Instead of compiling CockroachDB from the source code or using the operating system's native package manager to install CockroachDB, you are going to use the [Docker image for CockroachDB](https://hub.docker.com/r/cockroachdb/cockroach) and run it in a container.
|
||||
|
||||
CockroachDB is compatible with PostgreSQL to a significant extent, and shares many conventions with the latter, particularly the default names for the environment variables. So, if you are familiar with Postgres, don't be surprised that we are going to use some familiar environment variables names. The Go modules that work with Postgres, such as [pgx](https://pkg.go.dev/github.com/jackc/pgx), [pq](https://pkg.go.dev/github.com/lib/pq), [GORM](https://gorm.io/index.html), and [upper/db](https://upper.io/v4/) also work with CockroachDB.
|
||||
CockroachDB is compatible with PostgreSQL to a significant extent, and shares many conventions with the latter, particularly the default names for the environment variables. So, if you are familiar with Postgres, don't be surprised if you see some familiar environment variables names. The Go modules that work with Postgres, such as [pgx](https://pkg.go.dev/github.com/jackc/pgx), [pq](https://pkg.go.dev/github.com/lib/pq), [GORM](https://gorm.io/index.html), and [upper/db](https://upper.io/v4/) also work with CockroachDB.
|
||||
|
||||
For more information on the relation between Go and CockroachDB, please refer to the [CockroachDB documentation](https://www.cockroachlabs.com/docs/v20.2/build-a-go-app-with-cockroachdb.html), although this is not necessary to continue with the present guide.
|
||||
For more information on the relation between Go and CockroachDB, refer to the [CockroachDB documentation](https://www.cockroachlabs.com/docs/v20.2/build-a-go-app-with-cockroachdb.html), although this isn't necessary to continue with the present guide.
|
||||
|
||||
### Storage
|
||||
|
||||
The point of a database is to have a persistent store of data. [Volumes](../../storage/volumes.md) are the preferred mechanism for persisting data generated by and used by Docker containers. Thus, before we start CockroachDB, let's create the volume for it.
|
||||
The point of a database is to have a persistent store of data. [Volumes](../../storage/volumes.md) are the preferred mechanism for persisting data generated by and used by Docker containers. Thus, before you start CockroachDB, create the volume for it.
|
||||
|
||||
To create a managed volume, run :
|
||||
|
||||
|
@ -35,7 +35,7 @@ $ docker volume create roach
|
|||
roach
|
||||
```
|
||||
|
||||
We can view the list of all managed volumes in our Docker instance with the following command:
|
||||
You can view the list of all managed volumes in your Docker instance with the following command:
|
||||
|
||||
```console
|
||||
$ docker volume list
|
||||
|
@ -45,7 +45,7 @@ local roach
|
|||
|
||||
### Networking
|
||||
|
||||
The example application and the database engine are going to talk to one another over the network. There are different kinds of network configuration possible, and we are going to use what is called a user-defined _bridge network_. It is going to provide us with a DNS lookup service so that we can refer to our database engine container by its hostname.
|
||||
The example application and the database engine are going to talk to one another over the network. There are different kinds of network configuration possible, and you're going to use what's called a user-defined bridge network. It is going to provide you with a DNS lookup service so that you can refer to your database engine container by its hostname.
|
||||
|
||||
The following command creates a new bridge network named `mynet`:
|
||||
|
||||
|
@ -65,17 +65,17 @@ daed20bbecce host host local
|
|||
6aee44f40a39 none null local
|
||||
```
|
||||
|
||||
Our bridge network `mynet` has been created successfully. The other three networks, named `bridge`, `host`, and `none` are the _default_ networks and they had been created by the Docker itself. While it is not relevant to our current discussion, you can learn more about Docker networking in the [networking overview](../../network/index.md) section.
|
||||
Your bridge network `mynet` has been created successfully. The other three networks, named `bridge`, `host`, and `none` are the default networks and they had been created by the Docker itself. While it's not relevant to this guide, you can learn more about Docker networking in the [networking overview](../../network/index.md) section.
|
||||
|
||||
### Choose good names for volumes and networks
|
||||
|
||||
As the saying goes, there are only two hard things in Computer Science: cache invalidation and naming things. And off-by-one errors.
|
||||
|
||||
When choosing a name for a network or a managed volume, it's best to choose a name that is indicative of the intended purpose. In this module, though, we aimed for brevity, so we settled for short, generic names.
|
||||
When choosing a name for a network or a managed volume, it's best to choose a name that's indicative of the intended purpose. This guide aims for brevity, so it used short, generic names.
|
||||
|
||||
### Start the database engine
|
||||
|
||||
Now that the housekeeping chores are done, we can run CockroachDB in a container and attach it to the volume and network we had just created. When you run the folllowing command, Docker will pull the image from Docker Hub and run it for you locally:
|
||||
Now that the housekeeping chores are done, you can run CockroachDB in a container and attach it to the volume and network you had just created. When you run the following command, Docker will pull the image from Docker Hub and run it for you locally:
|
||||
|
||||
```console
|
||||
$ docker run -d \
|
||||
|
@ -91,29 +91,29 @@ $ docker run -d \
|
|||
# ... output omitted ...
|
||||
```
|
||||
|
||||
Notice a clever use of the tag `latest-v20.1` to make sure that we are pulling the latest patch version of 20.1. The diversity of available tags depend on the image maintainer. Here, our intent was to have the latest patched version of CockroachDB while not straying too far away from the known working version as the time goes by. To see the tags available for CockroachDB image, we went to [CockroachDB page on Docker Hub](https://hub.docker.com/r/cockroachdb/cockroach/tags).
|
||||
Notice a clever use of the tag `latest-v20.1` to make sure that you're pulling the latest patch version of 20.1. The diversity of available tags depend on the image maintainer. Here, your intent was to have the latest patched version of CockroachDB while not straying too far away from the known working version as the time goes by. To see the tags available for the CockroachDB image, you can go to the [CockroachDB page on Docker Hub](https://hub.docker.com/r/cockroachdb/cockroach/tags).
|
||||
|
||||
### Configure the database engine
|
||||
|
||||
Now that the database engine is live, there is some configuration to do before our application can begin using it. Fortunately, it's not a lot. We must:
|
||||
Now that the database engine is live, there is some configuration to do before your application can begin using it. Fortunately, it's not a lot. You must:
|
||||
|
||||
1. Create a blank database.
|
||||
2. Register a new user account with the database engine.
|
||||
3. Grant that new user access rights to the database.
|
||||
|
||||
We can do that with the help of CockroachDB built-in SQL shell. To start the SQL shell in the _same_ container where the database engine is running, type:
|
||||
You can do that with the help of CockroachDB built-in SQL shell. To start the SQL shell in the same container where the database engine is running, type:
|
||||
|
||||
```console
|
||||
$ docker exec -it roach ./cockroach sql --insecure
|
||||
```
|
||||
|
||||
1. In the SQL shell, create the database that our example application is going to use:
|
||||
1. In the SQL shell, create the database that the example application is going to use:
|
||||
|
||||
```sql
|
||||
CREATE DATABASE mydb;
|
||||
```
|
||||
|
||||
2. Register a new SQL user account with the database engine. We pick the username `totoro`.
|
||||
2. Register a new SQL user account with the database engine. Use the username `totoro`.
|
||||
|
||||
```sql
|
||||
CREATE USER totoro;
|
||||
|
@ -125,9 +125,9 @@ $ docker exec -it roach ./cockroach sql --insecure
|
|||
GRANT ALL ON DATABASE mydb TO totoro;
|
||||
```
|
||||
|
||||
4. Type `quit` to exit the shell.
|
||||
4. Type `quit` to exit the shell.
|
||||
|
||||
An example of interaction with the SQL shell is presented below.
|
||||
The following is an example of interaction with the SQL shell.
|
||||
|
||||
|
||||
```console
|
||||
|
@ -164,12 +164,12 @@ oliver@hki:~$
|
|||
|
||||
### Meet the example application
|
||||
|
||||
Now that we have started and configured the database engine, we can switch our attention to the application.
|
||||
Now that you have started and configured the database engine, you can switch your attention to the application.
|
||||
|
||||
The example application for this module is an extended version of `docker-gs-ping` application we've used in the previous modules. You have two options:
|
||||
The example application for this module is an extended version of `docker-gs-ping` application you've used in the previous modules. You have two options:
|
||||
|
||||
* You can update your local copy of `docker-gs-ping` to match the new extended version presented in this chapter; or
|
||||
* You can clone the [docker/docker-gs-ping-roach](https://github.com/docker/docker-gs-ping-roach) repo. This latter approach is recommended.
|
||||
* You can clone the [docker/docker-gs-ping-roach](https://github.com/docker/docker-gs-ping-roach) repository. This latter approach is recommended.
|
||||
|
||||
To checkout the example application, run:
|
||||
|
||||
|
@ -182,19 +182,18 @@ The application's `main.go` now includes database initialization code, as well a
|
|||
|
||||
* An HTTP `POST` request to `/send` containing a `{ "value" : string }` JSON must save the value to the database.
|
||||
|
||||
We also have an update for another business requirement. The requirement _was_:
|
||||
You also have an update for another business requirement. The requirement was:
|
||||
|
||||
* The application responds with a text message containing a heart symbol ("`<3`") on requests to `/`.
|
||||
|
||||
And _now_ it's going to be:
|
||||
And now it's going to be:
|
||||
|
||||
* The application responds with the string containing the count of messages stored in the database, enclosed in the parentheses.
|
||||
* The application responds with the string containing the count of messages stored in the database, enclosed in the parentheses.
|
||||
|
||||
Example output: `Hello, Docker! (7)`
|
||||
|
||||
The full source code listing of `main.go` follows.
|
||||
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
|
@ -336,14 +335,13 @@ func countRecords(db *sql.DB) (int, error) {
|
|||
}
|
||||
```
|
||||
|
||||
The repository also includes the `Dockerfile`, which is almost exactly the same as the multi-stage `Dockerfile` introduced in the previous modules. It uses the official Docker Go image to build the application and then builds the final image by placing the compiled binary into the much slimmer, distroless image.
|
||||
|
||||
The repository also includes the `Dockerfile`, which is almost exactly the same as the multi-stage `Dockerfile` introduced in the previous modules. It uses the official Docker Go image to build the application and then builds the final image by placing the compiled binary into the much slimmer, "distroless" image.
|
||||
|
||||
Regardless of whether we had updated the old example application, or checked out the new one, this new Docker image has to be built to reflect the changes to the application source code.
|
||||
Regardless of whether you had updated the old example application, or checked out the new one, this new Docker image has to be built to reflect the changes to the application source code.
|
||||
|
||||
### Build the application
|
||||
|
||||
We can build the image with the familiar `build` command:
|
||||
You can build the image with the familiar `build` command:
|
||||
|
||||
```console
|
||||
$ docker build --tag docker-gs-ping-roach .
|
||||
|
@ -351,13 +349,13 @@ $ docker build --tag docker-gs-ping-roach .
|
|||
|
||||
### Run the application
|
||||
|
||||
Now, let’s run our container. This time we’ll need to set some environment variables so that our application would know how to access the database. For now, we’ll do this right in the `docker run` command. Later we will see a more convenient method with Docker Compose.
|
||||
Now, run your container. This time you'll need to set some environment variables so that your application knows how to access the database. For now, you’ll do this right in the `docker run` command. Later you'll see a more convenient method with Docker Compose.
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> Since we are running our CockroachDB cluster in "insecure" mode, the value for the password can be anything.
|
||||
>
|
||||
> **Don't run in insecure mode in production, though!**
|
||||
> Since you're running your CockroachDB cluster in insecure mode, the value for the password can be anything.
|
||||
>
|
||||
> In production, don't run in insecure mode.
|
||||
|
||||
```console
|
||||
$ docker run -it --rm -d \
|
||||
|
@ -374,7 +372,7 @@ $ docker run -it --rm -d \
|
|||
|
||||
There are a few points to note about this command.
|
||||
|
||||
* We map container port `8080` to host port `80` this time. Thus, for `GET` requests we can get away with _literally_ `curl localhost`:
|
||||
* You map container port `8080` to host port `80` this time. Thus, for `GET` requests you can get away with literally `curl localhost`:
|
||||
|
||||
```console
|
||||
$ curl localhost
|
||||
|
@ -388,11 +386,11 @@ There are a few points to note about this command.
|
|||
Hello, Docker! (0)
|
||||
```
|
||||
|
||||
* The total number of stored messages is `0` for now. This is fine, because we had not posted anything to our application yet.
|
||||
* We refer to the database container by its hostname, which is `db`. This is what we had the `--hostname db` for when we started the database container.
|
||||
* The total number of stored messages is `0` for now. This is fine, because you haven't posted anything to your application yet.
|
||||
* You refer to the database container by its hostname, which is `db`. This is why you had `--hostname db` when you started the database container.
|
||||
|
||||
* The actual password does not matter, but it must be set to something to avoid confusing the example application.
|
||||
* The container we've just run is named `rest-server`. These names are useful for managing the container lifecycle:
|
||||
* The actual password doesn't matter, but it must be set to something to avoid confusing the example application.
|
||||
* The container you've just run is named `rest-server`. These names are useful for managing the container lifecycle:
|
||||
|
||||
```console
|
||||
# Don't do this just yet, it's only an example:
|
||||
|
@ -401,7 +399,7 @@ There are a few points to note about this command.
|
|||
|
||||
### Test the application
|
||||
|
||||
In the previous section, we have already tested querying our application with `GET` and it returned zero for the stored message counter. Now, let's post some messages to it:
|
||||
In the previous section, you've already tested querying your application with `GET` and it returned zero for the stored message counter. Now, post some messages to it:
|
||||
|
||||
```console
|
||||
$ curl --request POST \
|
||||
|
@ -410,13 +408,13 @@ $ curl --request POST \
|
|||
--data '{"value": "Hello, Docker!"}'
|
||||
```
|
||||
|
||||
The application responds with the contents of the message, which means it had been saved in the database:
|
||||
The application responds with the contents of the message, which means it has been saved in the database:
|
||||
|
||||
```json
|
||||
{"value":"Hello, Docker!"}
|
||||
```
|
||||
|
||||
Let's send another message:
|
||||
Send another message:
|
||||
|
||||
```console
|
||||
$ curl --request POST \
|
||||
|
@ -425,22 +423,22 @@ $ curl --request POST \
|
|||
--data '{"value": "Hello, Oliver!"}'
|
||||
```
|
||||
|
||||
And again, we get the value of the message back:
|
||||
And again, you get the value of the message back:
|
||||
|
||||
```json
|
||||
{"value":"Hello, Oliver!"}
|
||||
```
|
||||
|
||||
Let's see what the message counter says:
|
||||
Run curl and see what the message counter says:
|
||||
|
||||
```console
|
||||
$ curl localhost
|
||||
Hello, Docker! (2)
|
||||
```
|
||||
|
||||
Hey, that's exactly right! We sent two messages and the database kept them. Or has it? Let's stop and remove all our containers, but not the volumes, and try again.
|
||||
In this example, you sent two messages and the database kept them. Or has it? Stop and remove all your containers, but not the volumes, and try again.
|
||||
|
||||
First, let's stop the containers:
|
||||
First, stop the containers:
|
||||
|
||||
```console
|
||||
$ docker container stop rest-server roach
|
||||
|
@ -448,7 +446,7 @@ rest-server
|
|||
roach
|
||||
```
|
||||
|
||||
Then, let's remove them:
|
||||
Then, remove them:
|
||||
|
||||
```console
|
||||
$ docker container rm rest-server roach
|
||||
|
@ -456,7 +454,7 @@ rest-server
|
|||
roach
|
||||
```
|
||||
|
||||
Verify that they are gone:
|
||||
Verify that they're gone:
|
||||
|
||||
```console
|
||||
$ docker container list --all
|
||||
|
@ -492,20 +490,18 @@ $ docker run -it --rm -d \
|
|||
docker-gs-ping-roach
|
||||
```
|
||||
|
||||
Lastly, let's query our service:
|
||||
Lastly, query your service:
|
||||
|
||||
```console
|
||||
$ curl localhost
|
||||
Hello, Docker! (2)
|
||||
```
|
||||
|
||||
Great! The count of records from the database is correct although we had not only _stopped_ the containers, but also removed them before starting new instances. The difference is in the managed volume for CockroachDB, which we had reused. The new CockroachDB container has read the database files from the disk, just as it normally would if it were running outside the container.
|
||||
|
||||
Such is the power of managed volumes. Use it wisely.
|
||||
Great! The count of records from the database is correct although you haven't only stopped the containers, but you've also removed them before starting new instances. The difference is in the managed volume for CockroachDB, which you reused. The new CockroachDB container has read the database files from the disk, just as it normally would if it were running outside the container.
|
||||
|
||||
### Wind down everything
|
||||
|
||||
Remember, that we are running CockroachDB in "insecure" mode. Now that we had built and tested our application, it's time to wind everything down before moving on. You can list the containers that you are running with the `list` command:
|
||||
Remember, that you're running CockroachDB in insecure mode. Now that you've built and tested your application, it's time to wind everything down before moving on. You can list the containers that you are running with the `list` command:
|
||||
|
||||
```console
|
||||
$ docker container list
|
||||
|
@ -513,17 +509,17 @@ $ docker container list
|
|||
|
||||
Now that you know the container IDs, you can use `docker container stop` and `docker container rm`, as demonstrated in the previous modules.
|
||||
|
||||
Please make sure that you stop the CockroachDB and `docker-gs-ping-roach` containers before moving on.
|
||||
Stop the CockroachDB and `docker-gs-ping-roach` containers before moving on.
|
||||
|
||||
## Better productivity with Docker Compose
|
||||
|
||||
At this point, you might be wondering if there is a way to avoid having to deal with long lists of arguments to the `docker` command. The toy example we used in this series requires five environment variables to define the connection to the database. A real application might need many, _many_ more. Then there is also a question of dependencies – ideally, we would like to make sure that the database is started _before_ our application is run. And spinning up the database instance may require another Docker command with many options. But there is a better way to orchestrate these deployments for local development purposes.
|
||||
At this point, you might be wondering if there is a way to avoid having to deal with long lists of arguments to the `docker` command. The toy example you used in this series requires five environment variables to define the connection to the database. A real application might need many, many more. Then there is also a question of dependencies. Ideally, you want to make sure that the database is started before your application is run. And spinning up the database instance may require another Docker command with many options. But there is a better way to orchestrate these deployments for local development purposes.
|
||||
|
||||
In this section, we’ll create a Docker Compose file to start our `docker-gs-ping-roach` application and CockroachDB database engine with a single command.
|
||||
In this section, you'll create a Docker Compose file to start your `docker-gs-ping-roach` application and CockroachDB database engine with a single command.
|
||||
|
||||
### Configure Docker Compose
|
||||
|
||||
In our application's directory, create a new text file named `docker-compose.yml` with the following content.
|
||||
In your application's directory, create a new text file named `docker-compose.yml` with the following content.
|
||||
|
||||
|
||||
```yaml
|
||||
|
@ -531,7 +527,7 @@ version: '3.8'
|
|||
|
||||
services:
|
||||
docker-gs-ping-roach:
|
||||
depends_on:
|
||||
depends_on:
|
||||
- roach
|
||||
build:
|
||||
context: .
|
||||
|
@ -572,35 +568,35 @@ networks:
|
|||
```
|
||||
|
||||
|
||||
This Docker Compose configuration is super convenient as we do not have to type all the parameters to pass to the `docker run` command. We can declaratively do that in the Docker Compose file. The [Docker Compose documentation pages](../../compose/index.md) are quite extensive and include a full reference for the Docker Compose file format.
|
||||
This Docker Compose configuration is super convenient as you don't have to type all the parameters to pass to the `docker run` command. You can declaratively do that in the Docker Compose file. The [Docker Compose documentation pages](../../compose/index.md) are quite extensive and include a full reference for the Docker Compose file format.
|
||||
|
||||
### The `.env` file
|
||||
|
||||
Docker Compose will automatically read environment variables from a `.env` file if it is available. Since our Compose file requires `PGPASSWORD` to be set, we add the following content to the `.env` file:
|
||||
Docker Compose will automatically read environment variables from a `.env` file if it's available. Since your Compose file requires `PGPASSWORD` to be set, add the following content to the `.env` file:
|
||||
|
||||
```bash
|
||||
PGPASSWORD=whatever
|
||||
```
|
||||
|
||||
The exact value does not really matter for our example, because we run CockroachDB in `insecure` mode, but we have to set the variable to _some_ value to avoid getting an error.
|
||||
The exact value doesn't really matter for this example, because you run CockroachDB in insecure mode. Make sure you set the variable to some value to avoid getting an error.
|
||||
|
||||
### Merging Compose files
|
||||
|
||||
The file name `docker-compose.yml` is the default file name which `docker compose` command recognises if no `-f` flag is provided. This means you can have multiple Docker Compose files if your environment has such requirements. Furthermore, Docker Compose files are... composable (pun intended), so multiple files can be specified on the command line to merge parts of the configuration together. The following list is just a few examples of scenarios where such a feature would be very useful:
|
||||
The file name `docker-compose.yml` is the default file name which `docker compose` command recognizes if no `-f` flag is provided. This means you can have multiple Docker Compose files if your environment has such requirements. Furthermore, Docker Compose files are... composable (pun intended), so multiple files can be specified on the command line to merge parts of the configuration together. The following list is just a few examples of scenarios where such a feature would be very useful:
|
||||
|
||||
* Using a bind mount for the source code for local development but not when running the CI tests;
|
||||
* Switching between using a pre-built image for the frontend for some API application vs creating a bind mount for source code;
|
||||
* Adding additional services for integration testing;
|
||||
* And many more...
|
||||
|
||||
We are not going to cover any of these advanced use cases here.
|
||||
You aren't going to cover any of these advanced use cases here.
|
||||
|
||||
### Variable substitution in Docker Compose
|
||||
|
||||
One of the really cool features of Docker Compose is [variable substitution](../../compose/compose-file/compose-file-v3.md#variable-substitution). You can see some examples in our Compose file, `environment` section. By means of an example:
|
||||
One of the really cool features of Docker Compose is [variable substitution](../../compose/compose-file/compose-file-v3.md#variable-substitution). You can see some examples in the Compose file, `environment` section. By means of an example:
|
||||
|
||||
* `PGUSER=${PGUSER:-totoro}` means that inside the container, the environment variable `PGUSER` shall be set to the same value as it has on the host machine where Docker Compose is run. If there is no environment variable with this name on the host machine, the variable inside the container gets the default value of `totoro`.
|
||||
* `PGPASSWORD=${PGPASSWORD:?database password not set}` means that if the environment variable `PGPASSWORD` is not set on the host, Docker Compose will display an error. This is OK, because we don't want to hard-code default values for the password. We set the password value in the `.env` file, which is local to our machine. It is always a good idea to add `.env` to `.gitignore` to prevent the secrets being checked into the version control.
|
||||
* `PGPASSWORD=${PGPASSWORD:?database password not set}` means that if the environment variable `PGPASSWORD` isn't set on the host, Docker Compose will display an error. This is OK, because you don't want to hard-code default values for the password. You set the password value in the `.env` file, which is local to your machine. It is always a good idea to add `.env` to `.gitignore` to prevent the secrets being checked into the version control.
|
||||
|
||||
Other ways of dealing with undefined or empty values exist, as documented in the [variable substitution](../../compose/compose-file/compose-file-v3.md#variable-substitution) section of the Docker documentation.
|
||||
|
||||
|
@ -612,23 +608,23 @@ Before you apply changes made to a Compose configuration file, there is an oppor
|
|||
$ docker compose config
|
||||
```
|
||||
|
||||
When this command is run, Docker Compose would read the file `docker-compose.yml`, parse it into a data structure in memory, validate where possible, and print back the _reconstruction_ of that configuration file from its internal representation. If this is not possible due to errors, it would print an error message instead.
|
||||
When this command is run, Docker Compose reads the file `docker-compose.yml`, parses it into a data structure in memory, validates where possible, and prints back the reconstruction of that configuration file from its internal representation. If this isn't possible due to errors, Docker prints an error message instead.
|
||||
|
||||
### Build and run the application using Docker Compose
|
||||
|
||||
Let’s start our application and confirm that it is running properly.
|
||||
Start your application and confirm that it's running.
|
||||
|
||||
```console
|
||||
$ docker compose up --build
|
||||
```
|
||||
|
||||
We pass the `--build` flag so Docker will compile our image and then starts it.
|
||||
You passed the `--build` flag so Docker will compile your image and then start it.
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> Docker Compose is a useful tool, but it has its own quirks. For example, no rebuild is triggered on the update to the source code unless the `--build` flag is provided. It is a very common pitfall to edit one's source code, and forget to use the `--build` flag when running `docker compose up`.
|
||||
|
||||
Since our set-up is now run by Docker Compose, it has assigned it a "project name", so we got a new volume for our CockroachDB instance. This means that our application would fail to connect to the database, because the database does not exist in this new volume. The terminal would display an authentication error for the database:
|
||||
Since your set-up is now run by Docker Compose, it has assigned it a project name, so you get a new volume for your CockroachDB instance. This means that your application will fail to connect to the database, because the database doesn't exist in this new volume. The terminal displays an authentication error for the database:
|
||||
|
||||
```
|
||||
# ... omitted output ...
|
||||
|
@ -661,23 +657,23 @@ rest-server exited with code 1
|
|||
# ... omitted output ...
|
||||
```
|
||||
|
||||
Because of the way we set up our deployment using `restart_policy`, the failing container is being restarted every 20 seconds. So, in order to fix the problem, we need to log into the database engine and create the user, we've done it before in [Configure the database engine](#configure-the-database-engine).
|
||||
Because of the way you set up your deployment using `restart_policy`, the failing container is being restarted every 20 seconds. So, in order to fix the problem, you need to log in to the database engine and create the user. You've done it before in [Configure the database engine](#configure-the-database-engine).
|
||||
|
||||
This is not a big deal. All we have to do is to connect to CockroachDB instance and run the three SQL commands to create the database and the user, as described above in the _Configure the database engine_ section above.
|
||||
This isn't a big deal. All you have to do is to connect to CockroachDB instance and run the three SQL commands to create the database and the user, as described in [Configure the database engine](#configure-the-database-engine).
|
||||
|
||||
So we login into the database engine from another terminal:
|
||||
So, log in to the database engine from another terminal:
|
||||
|
||||
```console
|
||||
$ docker exec -it roach ./cockroach sql --insecure
|
||||
```
|
||||
|
||||
And execute the same commands as before to create the database `mydb`, the user `totoro`, and to grant that user necessary permissions. Once we do that (and the example application container is automatically restarted), the `rest-service` stops failing and restarting and the console goes quiet.
|
||||
And run the same commands as before to create the database `mydb`, the user `totoro`, and to grant that user necessary permissions. Once you do that (and the example application container is automatically restarts), the `rest-service` stops failing and restarting and the console goes quiet.
|
||||
|
||||
It would have been possible to connect the volume that we had previously used, but for the purposes of our example it's more trouble than it's worth and it also provided an opportunity to show how to introduce resilience into our deployment via the `restart_policy` Compose file feature.
|
||||
It would have been possible to connect the volume that you had previously used, but for the purposes of this example it's more trouble than it's worth and it also provided an opportunity to show how to introduce resilience into your deployment via the `restart_policy` Compose file feature.
|
||||
|
||||
### Testing the application
|
||||
|
||||
Now let’s test our API endpoint. In the new terminal, run the following command:
|
||||
Now, test your API endpoint. In the new terminal, run the following command:
|
||||
|
||||
```console
|
||||
$ curl http://localhost/
|
||||
|
@ -691,11 +687,11 @@ Hello, Docker! (0)
|
|||
|
||||
### Shutting down
|
||||
|
||||
To _stop_ the containers started by Docker Compose, press ctrl+c in the terminal where we run `docker compose up`. To _remove_ those containers after they had been stopped, run `docker compose down`.
|
||||
To stop the containers started by Docker Compose, press `ctrl+c` in the terminal where you ran `docker compose up`. To remove those containers after they've been stopped, run `docker compose down`.
|
||||
|
||||
### Detached mode
|
||||
|
||||
You can run containers started by the `docker compose` command in detached mode, just as you would with the `docker` command, by using the `-d` flag.
|
||||
You can run containers started by the `docker compose` command in detached mode, just as you would with the `docker` command, by using the `-d` flag.
|
||||
|
||||
To start the stack, defined by the Compose file in detached mode, run:
|
||||
|
||||
|
@ -707,7 +703,7 @@ Then, you can use `docker compose stop` to stop the containers and `docker compo
|
|||
|
||||
## Further exploration
|
||||
|
||||
We would suggest running `docker compose` to see what other commands are available.
|
||||
You can run `docker compose` to see what other commands are available.
|
||||
|
||||
## Wrap up
|
||||
|
||||
|
@ -715,13 +711,13 @@ There are some tangential, yet interesting points that were purposefully not cov
|
|||
|
||||
### Persistent storage
|
||||
|
||||
A _managed volume_ isn't the only way to provide your container with persistent storage. It is highly recommended to get acquainted with available storage options and their use cases, covered in the following part of Docker documentation: [Manage data in Docker](../../storage/index.md).
|
||||
A managed volume isn't the only way to provide your container with persistent storage. It is highly recommended to get acquainted with available storage options and their use cases, covered in [Manage data in Docker](../../storage/_index.md).
|
||||
|
||||
### CockroachDB clusters
|
||||
|
||||
We run a single instance of CockroachDB, which was enough for our demonstration. But it is possible to run a CockroachDB _cluster_, which is made of multiple instances of CockroachDB, each instance running in its own container. Since CockroachDB engine is distributed by design, it would have taken us surprisingly little change to our procedure to run a cluster with multiple nodes.
|
||||
You ran a single instance of CockroachDB, which was enough for this example. But, it's possible to run a CockroachDB cluster, which is made of multiple instances of CockroachDB, each instance running in its own container. Since CockroachDB engine is distributed by design, it would have taken surprisingly little change to your procedure to run a cluster with multiple nodes.
|
||||
|
||||
Such distributed set-up offers interesting possibilities, such as applying _Chaos Engineering_ techniques to simulate parts of the cluster failing and evaluating our application's ability to cope with such failures.
|
||||
Such distributed set-up offers interesting possibilities, such as applying Chaos Engineering techniques to simulate parts of the cluster failing and evaluating your application's ability to cope with such failures.
|
||||
|
||||
If you are interested in experimenting with CockroachDB clusters, check out:
|
||||
|
||||
|
@ -730,16 +726,12 @@ If you are interested in experimenting with CockroachDB clusters, check out:
|
|||
|
||||
### Other databases
|
||||
|
||||
Since we did not run a cluster of CockroachDB instances, you might be wondering whether we could have used a non-distributed database engine. The answer is 'yes', and if we were to pick a more traditional SQL database, such as [PostgreSQL](https://www.postgresql.org/), the process described in this chapter would have been very similar.
|
||||
Since you didn't run a cluster of CockroachDB instances, you might be wondering whether you could have used a non-distributed database engine. The answer is 'yes', and if you were to pick a more traditional SQL database, such as [PostgreSQL](https://www.postgresql.org/), the process described in this chapter would have been very similar.
|
||||
|
||||
## Next steps
|
||||
|
||||
In this module, we set up a containerised development environment with our application and the database engine running in different containers. We also wrote a Docker Compose file which links the two containers together and provides for easy starting up and tearing down of the development environment.
|
||||
In this module, you set up a containerized development environment with your application and the database engine running in different containers. You also wrote a Docker Compose file which links the two containers together and provides for easy starting up and tearing down of the development environment.
|
||||
|
||||
In the next module, we’ll take a look at one possible approach to running functional tests in Docker. See:
|
||||
In the next module, you'll take a look at one possible approach to running functional tests in Docker.
|
||||
|
||||
{{< button text="Run your tests" url="run-tests.md" >}}
|
||||
|
||||
## Feedback
|
||||
|
||||
Help us improve this topic by providing your feedback. Let us know what you think by creating an issue in the [Docker Docs]({{% param "repo" %}}/issues/new?title=[Golang%20docs%20feedback]) GitHub repository. Alternatively, [create a PR]({{% param "repo" %}}/pulls) to suggest updates.
|
||||
{{< button text="Run your tests" url="run-tests.md" >}}
|
|
@ -8,15 +8,15 @@ aliases:
|
|||
|
||||
## Prerequisites
|
||||
|
||||
Work through the steps to dockerize a Go application in [Build your Go image](build-images.md).
|
||||
Work through the steps to containerize a Go application in [Build your Go image](build-images.md).
|
||||
|
||||
## Overview
|
||||
|
||||
In the previous module we created a `Dockerfile` for our example application and then we created our Docker image using the command `docker build`. Now that we have the image, we can run that image and see if our application is running correctly.
|
||||
In the previous module you created a `Dockerfile` for your example application and then you created your Docker image using the command `docker build`. Now that you have the image, you can run that image and see if your application is running correctly.
|
||||
|
||||
A container is a normal operating system process except that this process is isolated and has its own file system, its own networking, and its own isolated process tree separate from the host.
|
||||
|
||||
To run an image inside of a container, we use the `docker run` command. It requires one parameter and that is the image name. Let’s start our image and make sure it is running correctly. Execute the following command in your terminal.
|
||||
To run an image inside of a container, you use the `docker run` command. It requires one parameter and that's the image name. Start your image and make sure it's running correctly. Run the following command in your terminal.
|
||||
|
||||
```console
|
||||
$ docker run docker-gs-ping
|
||||
|
@ -34,20 +34,24 @@ ____________________________________O/_______
|
|||
⇨ http server started on [::]:8080
|
||||
```
|
||||
|
||||
When you run this command, you’ll notice that you were not returned to the command prompt. This is because our application is a REST server and will run in a loop waiting for incoming requests without returning control back to the OS until we stop the container.
|
||||
When you run this command, you’ll notice that you weren't returned to the command prompt. This is because your application is a REST server and will run in a loop waiting for incoming requests without returning control back to the OS until you stop the container.
|
||||
|
||||
Let’s make a GET request to the server using the curl command.
|
||||
Make a GET request to the server using the curl command.
|
||||
|
||||
```console
|
||||
$ curl http://localhost:8080/
|
||||
curl: (7) Failed to connect to localhost port 8080: Connection refused
|
||||
```
|
||||
|
||||
Our curl command failed because the connection to our server was refused. Meaning that we were not able to connect to localhost on port 8080. This is expected because our container is running in isolation which includes networking. Let’s stop the container and restart with port 8080 published on our local network.
|
||||
Your curl command failed because the connection to your server was refused.
|
||||
Meaning that you weren't able to connect to localhost on port 8080. This is
|
||||
expected because your container is running in isolation which includes
|
||||
networking. Stop the container and restart with port 8080 published on your
|
||||
local network.
|
||||
|
||||
To stop the container, press ctrl-c. This will return you to the terminal prompt.
|
||||
|
||||
To publish a port for our container, we’ll use the `--publish` flag (`-p` for short) on the docker run command. The format of the `--publish` command is `[host_port]:[container_port]`. So if we wanted to expose port `8080` inside the container to port `3000` outside the container, we would pass `3000:8080` to the `--publish` flag.
|
||||
To publish a port for your container, you’ll use the `--publish` flag (`-p` for short) on the `docker run` command. The format of the `--publish` command is `[host_port]:[container_port]`. So if you wanted to expose port `8080` inside the container to port `3000` outside the container, you would pass `3000:8080` to the `--publish` flag.
|
||||
|
||||
Start the container and expose port `8080` to port `8080` on the host.
|
||||
|
||||
|
@ -55,29 +59,34 @@ Start the container and expose port `8080` to port `8080` on the host.
|
|||
$ docker run --publish 8080:8080 docker-gs-ping
|
||||
```
|
||||
|
||||
Now let’s rerun the curl command from above.
|
||||
Now, rerun the curl command.
|
||||
|
||||
```console
|
||||
$ curl http://localhost:8080/
|
||||
Hello, Docker! <3
|
||||
```
|
||||
|
||||
Success! We were able to connect to the application running inside of our container on port 8080. Switch back to the terminal where your container is running and you should see the `GET` request logged to the console.
|
||||
Success! You were able to connect to the application running inside of your container on port 8080. Switch back to the terminal where your container is running and you should see the `GET` request logged to the console.
|
||||
|
||||
Press **ctrl-c** to stop the container.
|
||||
Press `ctrl-c` to stop the container.
|
||||
|
||||
## Run in detached mode
|
||||
|
||||
This is great so far, but our sample application is a web server and we should not have to have our terminal connected to the container. Docker can run your container in detached mode, that is in the background. To do this, we can use the `--detach` or `-d` for short. Docker will start your container the same as before but this time will “detach” from the container and return you to the terminal prompt.
|
||||
This is great so far, but your sample application is a web server and you
|
||||
shouldn't have to have your terminal connected to the container. Docker can run
|
||||
your container in detached mode in the background. To do this, you can use the
|
||||
`--detach` or `-d` for short. Docker will start your container the same as
|
||||
before but this time will detach from the container and return you to the
|
||||
terminal prompt.
|
||||
|
||||
```console
|
||||
$ docker run -d -p 8080:8080 docker-gs-ping
|
||||
d75e61fcad1e0c0eca69a3f767be6ba28a66625ce4dc42201a8a323e8313c14e
|
||||
```
|
||||
|
||||
Docker started our container in the background and printed the container ID on the terminal.
|
||||
Docker started your container in the background and printed the container ID on the terminal.
|
||||
|
||||
Again, let’s make sure that our container is running properly. Run the same `curl` command:
|
||||
Again, make sure that your container is running. Run the same `curl` command:
|
||||
|
||||
```console
|
||||
$ curl http://localhost:8080/
|
||||
|
@ -86,7 +95,7 @@ Hello, Docker! <3
|
|||
|
||||
## List containers
|
||||
|
||||
Since we ran our container in the background, how do we know if our container is running or what other containers are running on our machine? Well, to see a list of containers running on our machine, run `docker ps`. This is similar to how the ps command is used to see a list of processes on a Linux machine.
|
||||
Since you ran your container in the background, how do you know if your container is running or what other containers are running on your machine? Well, to see a list of containers running on your machine, run `docker ps`. This is similar to how the ps command is used to see a list of processes on a Linux machine.
|
||||
|
||||
```console
|
||||
$ docker ps
|
||||
|
@ -95,9 +104,9 @@ CONTAINER ID IMAGE COMMAND CREATED STATUS
|
|||
d75e61fcad1e docker-gs-ping "/docker-gs-ping" 41 seconds ago Up 40 seconds 0.0.0.0:8080->8080/tcp inspiring_ishizaka
|
||||
```
|
||||
|
||||
The `ps` command tells us a bunch of stuff about our running containers. We can see the container ID, the image running inside the container, the command that was used to start the container, when it was created, the status, ports that are exposed, and the names of the container.
|
||||
The `ps` command tells you a bunch of stuff about your running containers. You can see the container ID, the image running inside the container, the command that was used to start the container, when it was created, the status, ports that are exposed, and the names of the container.
|
||||
|
||||
You are probably wondering where the name of our container is coming from. Since we didn’t provide a name for the container when we started it, Docker generated a random name. We’ll fix this in a minute but first we need to stop the container. To stop the container, run the `docker stop` command, passing the container's name or ID.
|
||||
You are probably wondering where the name of your container is coming from. Since you didn’t provide a name for the container when you started it, Docker generated a random name. You'll fix this in a minute but first you need to stop the container. To stop the container, run the `docker stop` command, passing the container's name or ID.
|
||||
|
||||
```console
|
||||
$ docker stop inspiring_ishizaka
|
||||
|
@ -114,7 +123,7 @@ CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
|||
|
||||
## Stop, start, and name containers
|
||||
|
||||
Docker containers can be started, stopped and restarted. When we stop a container, it is not removed but the status is changed to stopped and the process inside of the container is stopped. When we ran the `docker ps` command, the default output is to only show running containers. If we pass the `--all` or `-a` for short, we will see all containers on our system, that is stopped containers and running containers.
|
||||
Docker containers can be started, stopped and restarted. When you stop a container, it's not removed but the status is changed to stopped and the process inside of the container is stopped. When you ran the `docker ps` command, the default output is to only show running containers. If you pass the `--all` or `-a` for short, you will see all containers on your system, including stopped containers and running containers.
|
||||
|
||||
```console
|
||||
$ docker ps --all
|
||||
|
@ -126,9 +135,9 @@ aade1bf3d330 docker-gs-ping "/docker-gs-ping" 3 minutes ago Ex
|
|||
52d5ce3c15f0 docker-gs-ping "/docker-gs-ping" 9 minutes ago Exited (2) 3 minutes ago gifted_mestorf
|
||||
```
|
||||
|
||||
If you’ve been following along, you should see several containers listed. These are containers that we started and stopped but have not removed yet.
|
||||
If you’ve been following along, you should see several containers listed. These are containers that you started and stopped but haven't removed yet.
|
||||
|
||||
Let’s restart the container that we have just stopped. Locate the name of the container and replace the name of the container below in the restart command:
|
||||
Restart the container that you have just stopped. Locate the name of the container and replace the name of the container in the following `restart` command:
|
||||
|
||||
```console
|
||||
$ docker restart inspiring_ishizaka
|
||||
|
@ -146,22 +155,22 @@ aade1bf3d330 docker-gs-ping "/docker-gs-ping" 4 minutes ago Exited
|
|||
52d5ce3c15f0 docker-gs-ping "/docker-gs-ping" 10 minutes ago Exited (2) 4 minutes ago gifted_mestorf
|
||||
```
|
||||
|
||||
Notice that the container we just restarted has been started in detached mode and has port `8080` exposed. Also, note that the status of the container is “Up X seconds”. When you restart a container, it will be started with the same flags or commands that it was originally started with.
|
||||
Notice that the container you just restarted has been started in detached mode and has port `8080` exposed. Also, note that the status of the container is `Up X seconds`. When you restart a container, it will be started with the same flags or commands that it was originally started with.
|
||||
|
||||
Let’s stop and remove all of our containers and take a look at fixing the random naming issue.
|
||||
Stop and remove all of your containers and take a look at fixing the random naming issue.
|
||||
|
||||
Stop the container we just started. Find the name of your running container and replace the name in the command below with the name of the container on your system:
|
||||
Stop the container you just started. Find the name of your running container and replace the name in the following command with the name of the container on your system:
|
||||
|
||||
```console
|
||||
$ docker stop inspiring_ishizaka
|
||||
inspiring_ishizaka
|
||||
```
|
||||
|
||||
Now that all of our containers are stopped, let’s remove them. When a container is removed, it is no longer running nor is it in the stopped state. Instead, the process inside the container is terminated and the metadata for the container is removed.
|
||||
Now that all of your containers are stopped, remove them. When a container is removed, it's no longer running nor is it in the stopped state. Instead, the process inside the container is terminated and the metadata for the container is removed.
|
||||
|
||||
To remove a container, run the `docker rm` command passing the container name. You can pass multiple container names to the command in one command.
|
||||
|
||||
Again, make sure you replace the containers names in the below command with the container names from your system:
|
||||
Again, make sure you replace the containers names in the following command with the container names from your system:
|
||||
|
||||
```console
|
||||
$ docker rm inspiring_ishizaka wizardly_joliot magical_carson gifted_mestorf
|
||||
|
@ -174,9 +183,9 @@ gifted_mestorf
|
|||
|
||||
Run the `docker ps --all` command again to verify that all containers are gone.
|
||||
|
||||
Now let’s address the pesky random name issue. Standard practice is to name your containers for the simple reason that it is easier to identify what is running in the container and what application or service it is associated with. Just like good naming conventions for variables in your code makes it simpler to read. So goes naming your containers.
|
||||
Now, address the pesky random name issue. Standard practice is to name your containers for the simple reason that it's easier to identify what's running in the container and what application or service it's associated with. Just like good naming conventions for variables in your code makes it simpler to read. So goes naming your containers.
|
||||
|
||||
To name a container, we must pass the `--name` flag to the `run` command:
|
||||
To name a container, you must pass the `--name` flag to the `run` command:
|
||||
|
||||
```console
|
||||
$ docker run -d -p 8080:8080 --name rest-server docker-gs-ping
|
||||
|
@ -190,14 +199,10 @@ CONTAINER ID IMAGE COMMAND CREATED STATUS
|
|||
3bbc6a3102ea docker-gs-ping "/docker-gs-ping" 25 seconds ago Up 24 seconds 0.0.0.0:8080->8080/tcp rest-server
|
||||
```
|
||||
|
||||
Now, we can easily identify our container based on the name.
|
||||
Now, you can easily identify your container based on the name.
|
||||
|
||||
## Next steps
|
||||
|
||||
In this module, we learned how to run containers and publish ports. We also learned to manage the lifecycle of containers. We then discussed the importance of naming our containers so that they are more easily identifiable. In the next module, we’ll learn how to run a database in a container and connect it to our application. See:
|
||||
In this module, you learned how to run containers and publish ports. You also learned to manage the lifecycle of containers. You then learned the importance of naming your containers so that they're more easily identifiable. In the next module, you’ll learn how to run a database in a container and connect it to your application.
|
||||
|
||||
{{< button text="How to develop your application" url="develop.md" >}}
|
||||
|
||||
## Feedback
|
||||
|
||||
Help us improve this topic by providing your feedback. Let us know what you think by creating an issue in the [Docker Docs]({{% param "repo" %}}/issues/new?title=[Golang%20docs%20feedback]) GitHub repository. Alternatively, [create a PR]({{% param "repo" %}}/pulls) to suggest updates.
|
||||
|
|
|
@ -6,11 +6,11 @@ aliases:
|
|||
- /get-started/golang/run-tests/
|
||||
---
|
||||
|
||||
Testing is an essential part of modern software development. Yet, testing can mean a lot of things to different development teams. In the name of brevity, we'll only take a look at running isolated, high-level, functional tests.
|
||||
Testing is an essential part of modern software development. Yet, testing can mean a lot of things to different development teams. In the name of brevity, you'll only take a look at running isolated, high-level, functional tests.
|
||||
|
||||
## Test structure
|
||||
|
||||
Each test is meant to verify a single business requirement for our example application. The following test is an excerpt from `main_test.go` test suite in our example application.
|
||||
Each test is meant to verify a single business requirement for the example application. The following test is an excerpt from `main_test.go` test suite in the example application.
|
||||
|
||||
|
||||
```go
|
||||
|
@ -50,7 +50,7 @@ func TestRespondsWithLove(t *testing.T) {
|
|||
```
|
||||
|
||||
|
||||
As you can see, this is a high-level test, unconcerned with the implementation details of our example application.
|
||||
As you can see, this is a high-level test, unconcerned with the implementation details of the example application.
|
||||
|
||||
* the test is using [`ory/dockertest`](https://github.com/ory/dockertest) Go module;
|
||||
* the test assumes that the Docker engine instance is running on the same machine where the test is being run.
|
||||
|
@ -59,7 +59,7 @@ The second test in `main_test.go` has almost identical structure but it tests _a
|
|||
|
||||
## Run tests locally
|
||||
|
||||
In order to run the tests, we must make sure that our application Docker image is up-to-date.
|
||||
In order to run the tests, you must make sure that your application Docker image is up-to-date.
|
||||
|
||||
```console
|
||||
$ docker build -t docker-gs-ping:latest .
|
||||
|
@ -67,18 +67,18 @@ $ docker build -t docker-gs-ping:latest .
|
|||
...
|
||||
```
|
||||
|
||||
In the above example we've omitted most of the output, only displaying the first line indicating that the build was successful.
|
||||
The previous example omitted most of the output, only displaying the first line indicating that the build was successful.
|
||||
|
||||
Note, that the image is tagged with `latest` which is the same label we've chosen to use in our `main_test.go` tests.
|
||||
Note, that the image is tagged with `latest` which is the same label you've chosen to use in your `main_test.go` tests.
|
||||
|
||||
Now that the Docker image for our application had been built, we can run the tests that depend on it:
|
||||
Now that the Docker image for your application had been built, you can run the tests that depend on it:
|
||||
|
||||
```console
|
||||
$ go test ./...
|
||||
ok github.com/docker/docker-gs-ping 2.564s
|
||||
```
|
||||
|
||||
That was a bit... underwhelming? Let's ask it to print a bit more detail, just to be sure:
|
||||
Use the option to print a bit more detail, just to be sure:
|
||||
|
||||
```console
|
||||
$ go test -v ./...
|
||||
|
@ -92,16 +92,12 @@ PASS
|
|||
ok github.com/docker/docker-gs-ping 6.670s
|
||||
```
|
||||
|
||||
So, the tests do, indeed, pass. Note, how retrying using exponential back-off helped avoiding failing tests while the containers are being initialised. What happens in each test is that `ory/dockertest` module connects to the local Docker engine instance and instructs it to spin up a container using the image, identified by the tag `docker-gs-ping:latest`. Starting up a container may take a while, so our tests retry accessing the container until the container is ready to respond to requests.
|
||||
So, the tests do, indeed, pass. Note, how retrying using exponential back-off helped avoiding failing tests while the containers are being initialized. What happens in each test is that `ory/dockertest` module connects to the local Docker engine instance and instructs it to spin up a container using the image, identified by the tag `docker-gs-ping:latest`. Starting up a container may take a while, so your tests retry accessing the container until the container is ready to respond to requests.
|
||||
|
||||
## Next steps
|
||||
|
||||
In this module, we've seen an example of using Docker for isolated functional testing of an example Go application. There are many different ways to test an application and we have only considered the high-level, functional testing. This, however, feeds naturally into the next topic, where we are going to set up our tests to run in an automated pipeline.
|
||||
In this module, you've seen an example of using Docker for isolated functional testing of an example Go application. There are many different ways to test an application and you have only considered the high-level, functional testing. This, however, feeds naturally into the next topic, where you're going to set up your tests to run in an automated pipeline.
|
||||
|
||||
In the next module, we’ll take a look at how to set up a CI/CD pipeline using GitHub Actions. See:
|
||||
In the next module, you’ll take a look at how to set up a CI/CD pipeline using GitHub Actions.
|
||||
|
||||
{{< button text="Configure CI/CD" url="configure-ci-cd.md" >}}
|
||||
|
||||
## Feedback
|
||||
|
||||
Help us improve this topic by providing your feedback. Let us know what you think by creating an issue in the [Docker Docs]({{% param "repo" %}}/issues/new?title=[Golang%20docs%20feedback]) GitHub repository. Alternatively, [create a PR]({{% param "repo" %}}/pulls) to suggest updates.
|
||||
{{< button text="Configure CI/CD" url="configure-ci-cd.md" >}}
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Java language-specific guide
|
||||
keywords: Docker, getting started, java, language
|
||||
keywords: java, getting started
|
||||
description: Containerize Java apps using Docker
|
||||
toc_min: 1
|
||||
toc_max: 2
|
||||
|
@ -18,6 +18,6 @@ The Java getting started guide teaches you how to create a containerized Spring
|
|||
|
||||
After completing the Java getting started modules, you should be able to containerize your own Java application based on the examples and instructions provided in this guide.
|
||||
|
||||
Let’s get started!
|
||||
Get started building your first Java image.
|
||||
|
||||
{{< button text="Build your first Java image" url="build-images.md" >}}
|
|
@ -13,17 +13,17 @@ description: Learn how to build your first Docker image by writing a Dockerfile
|
|||
|
||||
## 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 needed to run an application - the code or binary, runtime, dependencies, and any other file system objects required.
|
||||
Now that you have a good overview of containers and the Docker platform, take a look at building your first image. An image includes everything needed to run an application - the code or binary, runtime, dependencies, and any other file system objects required.
|
||||
|
||||
To complete this tutorial, you need the following:
|
||||
|
||||
- Docker running locally. Follow the instructions to [download and install Docker](../../get-docker.md)
|
||||
- A Git client
|
||||
- An IDE or a text editor to edit files. We recommend using [IntelliJ Community Edition](https://www.jetbrains.com/idea/download/).
|
||||
- An IDE or a text editor to edit files. Docker recommends using [IntelliJ Community Edition](https://www.jetbrains.com/idea/download/).
|
||||
|
||||
## Sample application
|
||||
|
||||
Let’s clone the sample application that we'll be using in this module to our local development machine. Run the following commands in a terminal to clone the repo.
|
||||
Clone the sample application that you'll be using in this module to your local development machine. Run the following commands in a terminal to clone the repository.
|
||||
|
||||
```console
|
||||
$ cd /path/to/working/directory
|
||||
|
@ -33,19 +33,19 @@ $ cd spring-petclinic
|
|||
|
||||
## Test the application without Docker (optional)
|
||||
|
||||
In this step, we will test the application locally without Docker, before we
|
||||
In this step, you'll test the application locally without Docker, before you
|
||||
continue with building and running the application with Docker. This section
|
||||
requires you to have Java OpenJDK version 15 or later installed on your machine.
|
||||
[Download and install Java](https://jdk.java.net/)
|
||||
|
||||
If you prefer to not install Java on your machine, you can skip this step, and
|
||||
continue straight to the next section, in which we explain how to build and run
|
||||
the application in Docker, which does not require you to have Java installed on
|
||||
your machine.
|
||||
continue straight to the next section, in which you'll build and run the
|
||||
application in Docker. Building or running the application in Docker doesn't
|
||||
require you to have Java installed on your machine.
|
||||
|
||||
Let’s start our application and make sure it is running properly. Maven will manage all the project processes (compiling, tests, packaging, etc). The **Spring Pets Clinic** project we cloned earlier contains an embedded version of Maven. Therefore, we don't need to install Maven separately on your local machine.
|
||||
Start your application and make sure it's running. Maven will manage all the project processes (compiling, tests, packaging, etc). The **Spring Pets Clinic** project you cloned earlier contains an embedded version of Maven. Therefore, you don't need to install Maven on your local machine.
|
||||
|
||||
Open your terminal and navigate to the working directory we created and run the following command:
|
||||
Open your terminal and navigate to the working directory you created and run the following command:
|
||||
|
||||
```console
|
||||
$ ./mvnw spring-boot:run
|
||||
|
@ -53,27 +53,28 @@ $ ./mvnw spring-boot:run
|
|||
|
||||
This downloads the dependencies, builds the project, and starts it.
|
||||
|
||||
To test that the application is working properly, open a new browser and navigate to `http://localhost:8080`.
|
||||
To test that the application is working, open a new browser and navigate to `http://localhost:8080`.
|
||||
|
||||
Switch back to the terminal where our server is running and you should see the following requests in the server logs. The data will be different on your machine.
|
||||
Switch back to the terminal where your server is running and you should see the following requests in the server logs. The data will be different on your machine.
|
||||
|
||||
```console
|
||||
o.s.s.petclinic.PetClinicApplication : Started
|
||||
PetClinicApplication in 11.743 seconds (JVM running for 12.364)
|
||||
```
|
||||
|
||||
Great! We verified that the application works. At this stage, you've completed
|
||||
Great! You verified that the application works. At this stage, you've completed
|
||||
testing the server script locally.
|
||||
|
||||
Press `CTRL-c` from within the terminal session where the server is running to stop it.
|
||||
|
||||
|
||||
We will now continue to build and run the application in Docker.
|
||||
You'll now continue to build and run the application in Docker.
|
||||
|
||||
## Create a Dockerfile for Java
|
||||
|
||||
Next, we need to add a line in our Dockerfile that tells Docker what base image
|
||||
we would like to use for our application.
|
||||
Create a file named `Dockerfile` in the root of your project folder.
|
||||
|
||||
Next, you need to add a line in your Dockerfile that tells Docker what base
|
||||
image you would like to use for your application. Open the `Dockerfile` in an IDE or text editor, and then add the following contents.
|
||||
|
||||
```dockerfile
|
||||
# syntax=docker/dockerfile:1
|
||||
|
@ -81,48 +82,48 @@ we would like to use for our application.
|
|||
FROM eclipse-temurin:17-jdk-jammy
|
||||
```
|
||||
|
||||
Docker images can be inherited from other images. For this guide, we use Eclipse Temurin, one of the most popular official images with a build-worthy JDK.
|
||||
Docker images can be inherited from other images. For this guide, you use Eclipse Temurin, one of the most popular official images with a build-worthy JDK.
|
||||
|
||||
To make things easier when running the rest of our commands, let’s set the image's
|
||||
To make things easier when running the rest of your commands, set the image's
|
||||
working directory. This instructs Docker to use this path as the default location
|
||||
for all subsequent commands. By doing this, we do not have to type out full file
|
||||
for all subsequent commands. By doing this, you don't have to type out full file
|
||||
paths but can use relative paths based on the working directory.
|
||||
|
||||
```dockerfile
|
||||
WORKDIR /app
|
||||
```
|
||||
|
||||
Usually, the very first thing you do once you’ve downloaded a project written in
|
||||
Usually, the first thing you do once you’ve downloaded a project written in
|
||||
Java which is using Maven for project management is to install dependencies.
|
||||
|
||||
Before we can run `mvnw dependency`, we need to get the Maven wrapper and our
|
||||
`pom.xml` file into our image. We’ll use the `COPY` command to do this. The
|
||||
Before you can run `mvnw dependency`, you need to get the Maven wrapper and your
|
||||
`pom.xml` file into your image. You'll use the `COPY` command to do this. The
|
||||
`COPY` command takes two parameters. The first parameter tells Docker what
|
||||
file(s) you would like to copy into the image. The second parameter tells Docker
|
||||
where you want that file(s) to be copied to. We’ll copy all those files and
|
||||
directories into our working directory - `/app`.
|
||||
where you want that file(s) to be copied to. You'll copy all those files and
|
||||
directories into your working directory - `/app`.
|
||||
|
||||
```dockerfile
|
||||
COPY .mvn/ .mvn
|
||||
COPY mvnw pom.xml ./
|
||||
```
|
||||
|
||||
Once we have our `pom.xml` file inside the image, we can use the `RUN` command
|
||||
to execute the command `mvnw dependency:resolve`. This works exactly the same
|
||||
way as if we were running `mvnw` (or `mvn`) dependency locally on our machine,
|
||||
but this time the dependencies will be installed into the image.
|
||||
Once you have your `pom.xml` file inside the image, you can use the `RUN`
|
||||
command to run the command `mvnw dependency:resolve`. This works exactly the
|
||||
same way as if you were running `mvnw` (or `mvn`) dependency locally on your
|
||||
machine, but this time the dependencies will be installed into the image.
|
||||
|
||||
```dockerfile
|
||||
RUN ./mvnw dependency:resolve
|
||||
```
|
||||
|
||||
At this point, we have an Eclipse Temurin image that is based on OpenJDK version 17, and we have also installed our dependencies. The next thing we need to do is to add our source code into the image. We’ll use the `COPY` command just like we did with our `pom.xml` file above.
|
||||
At this point, you have an Eclipse Temurin image that's based on OpenJDK version 17, and you have also installed your dependencies. The next thing you need to do is to add your source code into the image. You'll use the `COPY` command just like you did with your `pom.xml` file in the previous steps.
|
||||
|
||||
```dockerfile
|
||||
COPY src ./src
|
||||
```
|
||||
|
||||
This `COPY` command takes all the files located in the current directory and copies them into the image. Now, all we have to do is to tell Docker what command we want to run when our image is executed inside a container. We do this using the `CMD` command.
|
||||
This `COPY` command takes all the files located in the current directory and copies them into the image. Now, all you have to do is to tell Docker what command you want to run when your image is ran inside a container. You do this using the `CMD` command.
|
||||
|
||||
```dockerfile
|
||||
CMD ["./mvnw", "spring-boot:run"]
|
||||
|
@ -148,7 +149,7 @@ CMD ["./mvnw", "spring-boot:run"]
|
|||
|
||||
### Create a `.dockerignore` file
|
||||
|
||||
To increase the performance of the build, and as a general best practice, we recommend that you create a `.dockerignore` file in the same directory as the Dockerfile. For this tutorial, your `.dockerignore` file should contain just one line:
|
||||
To increase the performance of the build, and as a general best practice, Docker recommends that you create a `.dockerignore` file in the same directory as the Dockerfile. For this tutorial, your `.dockerignore` file should contain just one line:
|
||||
|
||||
```
|
||||
target
|
||||
|
@ -161,11 +162,11 @@ file is good enough for now.
|
|||
|
||||
## Build an image
|
||||
|
||||
Now that we’ve created our Dockerfile, let’s build our image. To do this, we use the `docker build` command. The `docker build` command builds Docker images from a Dockerfile and a “context”. A build’s context is the set of files located in the specified PATH or URL. The Docker build process can access any of the files located in this context.
|
||||
Now that you’ve created our Dockerfile, build your image. To do this, you use the `docker build` command. The `docker build` command builds Docker images from a Dockerfile and a “context”. A build’s context is the set of files located in the specified PATH or URL. The Docker build process can access any of the files located in this context.
|
||||
|
||||
The build command optionally takes a `--tag` flag. The tag is used to set the name of the image and an optional tag in the format `name:tag`. We’ll leave off the optional `tag` for now to help simplify things. If we do not pass a tag, Docker uses “latest” as its default tag. You can see this in the last line of the build output.
|
||||
The build command optionally takes a `--tag` flag. The tag is used to set the name of the image and an optional tag in the format `name:tag`. You'll leave off the optional `tag` for now to help simplify things. If you don't pass a tag, Docker uses “latest” as its default tag. You can see this in the last line of the build output.
|
||||
|
||||
Let’s build our first Docker image.
|
||||
Build your first Docker image.
|
||||
|
||||
```console
|
||||
$ docker build --tag java-docker .
|
||||
|
@ -182,9 +183,9 @@ Successfully tagged java-docker:latest
|
|||
|
||||
## View local images
|
||||
|
||||
To see a list of images we have on our local machine, we have two options. One is to use the CLI and the other is to use [Docker Desktop](../../desktop/use-desktop/images.md). As we are currently working in the terminal let’s take a look at listing images using the CLI.
|
||||
To see a list of images you have on our local machine, you have two options. One is to use the CLI and the other is to use [Docker Desktop](../../desktop/use-desktop/images.md). As you are currently working in the terminal, list the images using the CLI.
|
||||
|
||||
To list images, simply run the `docker images` command.
|
||||
To list images, run the `docker images` command.
|
||||
|
||||
```console
|
||||
$ docker images
|
||||
|
@ -192,23 +193,23 @@ REPOSITORY TAG IMAGE ID CREATED SIZ
|
|||
java-docker latest b1b5f29f74f0 47 minutes ago 567MB
|
||||
```
|
||||
|
||||
You should see at least the image we just built `java-docker:latest`.
|
||||
You should see at least the image you just built `java-docker:latest`.
|
||||
|
||||
## Tag images
|
||||
|
||||
An image name is made up of slash-separated name components. Name components may contain lowercase letters, digits, and separators. A separator is defined as a period, one or two underscores, or one or more dashes. A name component may not start or end with a separator.
|
||||
|
||||
An image is made up of a manifest and a list of layers. Do not worry too much about manifests and layers at this point other than a “tag” points to a combination of these artifacts. You can have multiple tags for an image. Let’s create a second tag for the image we built and take a look at its layers.
|
||||
An image is made up of a manifest and a list of layers. Don't worry too much about manifests and layers at this point other than a “tag” points to a combination of these artifacts. You can have multiple tags for an image. Create a second tag for the image you built and take a look at its layers.
|
||||
|
||||
To create a new tag for the image we’ve built above, run the following command:
|
||||
To create a new tag for the image you’ve built in the previous steps, run the following command:
|
||||
|
||||
```console
|
||||
$ docker tag java-docker:latest java-docker:v1.0.0
|
||||
```
|
||||
|
||||
The `docker tag` command creates a new tag for an image. It does not create a new image. The tag points to the same image and is just another way to reference the image.
|
||||
The `docker tag` command creates a new tag for an image. It doesn't create a new image. The tag points to the same image and is just another way to reference the image.
|
||||
|
||||
Now, run the `docker images` command to see a list of our local images.
|
||||
Now, run the `docker images` command to see a list of your local images.
|
||||
|
||||
```console
|
||||
$ docker images
|
||||
|
@ -217,16 +218,16 @@ java-docker latest b1b5f29f74f0 59 minutes ago 567MB
|
|||
java-docker v1.0.0 b1b5f29f74f0 59 minutes ago 567MB
|
||||
```
|
||||
|
||||
You can see that we have two images that start with `java-docker`. We know they are the same image because if you take a look at the `IMAGE ID` column, you can see that the values are the same for the two images.
|
||||
You can see that you have two images that start with `java-docker`. You know they're the same image because if you take a look at the `IMAGE ID` column, you can see that the values are the same for the two images.
|
||||
|
||||
Let’s remove the tag that we just created. To do this, we’ll use the `rmi` command. The `rmi` command stands for “remove image”.
|
||||
Remove the tag that you just created. To do this, you’ll use the `rmi` command. The `rmi` command stands for “remove image”.
|
||||
|
||||
```console
|
||||
$ docker rmi java-docker:v1.0.0
|
||||
Untagged: java-docker:v1.0.0
|
||||
```
|
||||
|
||||
Note that the response from Docker tells us that the image has not been removed but only “untagged”. You can check this by running the `docker images` command.
|
||||
Note that the response from Docker tells you that the image hasn't been removed but only “untagged”. You can check this by running the `docker images` command.
|
||||
|
||||
```console
|
||||
$ docker images
|
||||
|
@ -234,14 +235,10 @@ REPOSITORY TAG IMAGE ID CREATED SIZE
|
|||
java-docker latest b1b5f29f74f0 59 minutes ago 567MB
|
||||
```
|
||||
|
||||
Our image that was tagged with `:v1.0.0` has been removed, but we still have the `java-docker:latest` tag available on our machine.
|
||||
Your image that was tagged with `:v1.0.0` has been removed, but you still have the `java-docker:latest` tag available on your machine.
|
||||
|
||||
## Next steps
|
||||
|
||||
In this module, we took a look at setting up our example Java application that we'll use for 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. In the next module, we’ll take a look at how to:
|
||||
In this module, you took a look at setting up an example Java application that you'll use for the rest of the tutorial. You also created a Dockerfile that you used to build your Docker image. Then, you took a look at tagging your images and removing images. In the next module, you’ll take a look at how to run your image as a container.
|
||||
|
||||
{{< button text="Run your image as a container" url="run-containers.md" >}}
|
||||
|
||||
## Feedback
|
||||
|
||||
Help us improve this topic by providing your feedback. Let us know what you think by creating an issue in the [Docker Docs]({{% param "repo" %}}/issues/new?title=[Java%20docs%20feedback]) GitHub repository. Alternatively, [create a PR]({{% param "repo" %}}/pulls) to suggest updates.
|
||||
{{< button text="Run your image as a container" url="run-containers.md" >}}
|
|
@ -10,12 +10,8 @@ description: Learn how to Configure CI/CD for your application
|
|||
|
||||
## Next steps
|
||||
|
||||
In this module, you have learnt how to set up GitHub Actions workflow to an existing Docker project, optimize your workflow to improve build times and reduce the number of pull requests, and finally, we learnt how to push only specific versions to Docker Hub. You can also set up nightly tests against the latest tag, test each PR, or do something more elegant with the tags we are using and make use of the Git tag for the same tag in our image.
|
||||
In this module, you have learned how to set up GitHub Actions workflow to an existing Docker project, optimize your workflow to improve build times, and reduce the number of pull requests. Finally, you learned how to push only specific versions to Docker Hub. You can also set up nightly tests against the latest tag, test each PR, or do something more elegant with the tags you're using and make use of the Git tag for the same tag in your image.
|
||||
|
||||
You can also consider deploying your application. For detailed instructions, see:
|
||||
You can also consider deploying your application.
|
||||
|
||||
{{< button text="Deploy your application" url="deploy.md" >}}
|
||||
|
||||
## Feedback
|
||||
|
||||
Help us improve this topic by providing your feedback. Let us know what you think by creating an issue in the [Docker Docs]({{% param "repo" %}}/issues/new?title=[Java%20docs%20feedback]) GitHub repository. Alternatively, [create a PR]({{% param "repo" %}}/pulls) to suggest updates.
|
||||
{{< button text="Deploy your application" url="deploy.md" >}}
|
|
@ -4,8 +4,4 @@ keywords: deploy, ACI, ECS, Java, local, development
|
|||
description: Learn how to deploy your application
|
||||
---
|
||||
|
||||
{{< include "deploy.md" >}}
|
||||
|
||||
## Feedback
|
||||
|
||||
Help us improve this topic by providing your feedback. Let us know what you think by creating an issue in the [Docker Docs]({{% param "repo" %}}/issues/new?title=[Java%20docs%20feedback]) GitHub repository. Alternatively, [create a PR]({{% param "repo" %}}/pulls) to suggest updates.
|
||||
{{< include "deploy.md" >}}
|
|
@ -10,30 +10,30 @@ Work through the steps to build an image and run it as a containerized applicati
|
|||
|
||||
## Introduction
|
||||
|
||||
In this module, we’ll walk through setting up a local development environment for the application we built in the previous modules. We’ll use Docker to build our images and Docker Compose to make everything a whole lot easier.
|
||||
In this module, you’ll walk through setting up a local development environment for the application you built in the previous modules. You’ll use Docker to build your images and Docker Compose to make everything a whole lot easier.
|
||||
|
||||
## Run a database in a container
|
||||
|
||||
First, we’ll take a look at running a database in a container and how we use volumes and networking to persist our data and allow our application to talk with the database. Then we’ll pull everything together into a Compose file which allows us to setup and run a local development environment with one command. Finally, we’ll take a look at connecting a debugger to our application running inside a container.
|
||||
First, you’ll take a look at running a database in a container and how you use volumes and networking to persist your data and allow your application to talk with the database. Then you’ll pull everything together into a Compose file which allows you to set up and run a local development environment with one command. Finally, you’ll take a look at connecting a debugger to your application running inside a container.
|
||||
|
||||
Instead of downloading MySQL, installing, configuring, and then running the MySQL database as a service, we can use the Docker Official Image for MySQL and run it in a container.
|
||||
Instead of downloading MySQL, installing, configuring, and then running the MySQL database as a service, you can use the Docker Official Image for MySQL and run it in a container.
|
||||
|
||||
Before we run MySQL in a container, we'll create a couple of volumes that Docker can manage to store our persistent data and configuration. Let’s use the managed volumes feature that Docker provides instead of using bind mounts. You can read all about [Using volumes](../../storage/volumes.md) in our documentation.
|
||||
Before you run MySQL in a container, you'll create a couple of volumes that Docker can manage to store your persistent data and configuration. Use the managed volumes feature that Docker provides instead of using bind mounts. For more details, see [Using volumes](../../storage/volumes.md).
|
||||
|
||||
Let’s create our volumes now. We’ll create one for the data and one for configuration of MySQL.
|
||||
Create your volumes now. You’ll create one for the data and one for configuration of MySQL.
|
||||
|
||||
```console
|
||||
$ docker volume create mysql_data
|
||||
$ docker volume create mysql_config
|
||||
```
|
||||
|
||||
Now we’ll create a network that our application and database will use to talk to each other. The network is called a user-defined bridge network and gives us a nice DNS lookup service which we can use when creating our connection string.
|
||||
Now you’ll create a network that your application and database will use to talk to each other. The network is called a user-defined bridge network and gives us a nice DNS lookup service which you can use when creating your connection string.
|
||||
|
||||
```console
|
||||
$ docker network create mysqlnet
|
||||
```
|
||||
|
||||
Now, let's run MySQL in a container and attach to the volumes and network we created above. Docker pulls the image from Hub and runs it locally.
|
||||
Now, run MySQL in a container and attach to the volumes and network you created. Docker pulls the image from Hub and runs it locally.
|
||||
|
||||
```console
|
||||
$ docker run -it --rm -d -v mysql_data:/var/lib/mysql \
|
||||
|
@ -45,21 +45,21 @@ $ docker run -it --rm -d -v mysql_data:/var/lib/mysql \
|
|||
-p 3306:3306 mysql:8.0
|
||||
```
|
||||
|
||||
Okay, now that we have a running MySQL, let’s update our Dockerfile to activate the MySQL Spring profile defined in the application and switch from an in-memory H2 database to the MySQL server we just created.
|
||||
Now that you have a running MySQL, update your Dockerfile to activate the MySQL Spring profile defined in the application and switch from an in-memory H2 database to the MySQL server you just created.
|
||||
|
||||
We only need to add the MySQL profile as an argument to the `CMD` definition.
|
||||
You only need to add the MySQL profile as an argument to the `CMD` definition.
|
||||
|
||||
```dockerfile
|
||||
CMD ["./mvnw", "spring-boot:run", "-Dspring-boot.run.profiles=mysql"]
|
||||
```
|
||||
|
||||
Let's build our image.
|
||||
Build your image.
|
||||
|
||||
```console
|
||||
$ docker build --tag java-docker .
|
||||
```
|
||||
|
||||
Now, let’s run our container. This time, we need to set the `MYSQL_URL` environment variable so that our application knows what connection string to use to access the database. We’ll do this using the `docker run` command.
|
||||
Now, run your container. This time, you need to set the `MYSQL_URL` environment variable so that your application knows what connection string to use to access the database. You’ll do this using the `docker run` command.
|
||||
|
||||
```console
|
||||
$ docker run --rm -d \
|
||||
|
@ -69,7 +69,7 @@ $ docker run --rm -d \
|
|||
-p 8080:8080 java-docker
|
||||
```
|
||||
|
||||
Let’s test that our application is connected to the database and is able to list Veterinarians.
|
||||
Test that your application is connected to the database and is able to list Veterinarians.
|
||||
|
||||
```console
|
||||
$ curl --request GET \
|
||||
|
@ -77,7 +77,7 @@ $ curl --request GET \
|
|||
--header 'content-type: application/json'
|
||||
```
|
||||
|
||||
You should receive the following json back from our service.
|
||||
You should receive the following json back from your service.
|
||||
|
||||
```json
|
||||
{"vetList":[{"id":1,"firstName":"James","lastName":"Carter","specialties":[],"nrOfSpecialties":0,"new":false},{"id":2,"firstName":"Helen","lastName":"Leary","specialties":[{"id":1,"name":"radiology","new":false}],"nrOfSpecialties":1,"new":false},{"id":3,"firstName":"Linda","lastName":"Douglas","specialties":[{"id":3,"name":"dentistry","new":false},{"id":2,"name":"surgery","new":false}],"nrOfSpecialties":2,"new":false},{"id":4,"firstName":"Rafael","lastName":"Ortega","specialties":[{"id":2,"name":"surgery","new":false}],"nrOfSpecialties":1,"new":false},{"id":5,"firstName":"Henry","lastName":"Stevens","specialties":[{"id":1,"name":"radiology","new":false}],"nrOfSpecialties":1,"new":false},{"id":6,"firstName":"Sharon","lastName":"Jenkins","specialties":[],"nrOfSpecialties":0,"new":false}]}
|
||||
|
@ -85,11 +85,11 @@ You should receive the following json back from our service.
|
|||
|
||||
## Multi-stage Dockerfile for development
|
||||
|
||||
Let’s take a look at updating our Dockerfile to produce a final image which is ready for production as well as a dedicated step to produce a development image.
|
||||
Now you can update your Dockerfile to produce a final image which is ready for production as well as a dedicated step to produce a development image.
|
||||
|
||||
We’ll also set up the Dockerfile to start the application in debug mode in the development container so that we can connect a debugger to the running Java process.
|
||||
You’ll also set up the Dockerfile to start the application in debug mode in the development container so that you can connect a debugger to the running Java process.
|
||||
|
||||
Below is a multi-stage Dockerfile that we will use to build our production image and our development image. Replace the contents of your Dockerfile with the following.
|
||||
The following is a multi-stage Dockerfile that you'll use to build your production image and your development image. Replace the contents of your Dockerfile with the following.
|
||||
|
||||
```dockerfile
|
||||
# syntax=docker/dockerfile:1
|
||||
|
@ -113,13 +113,13 @@ COPY --from=build /app/target/spring-petclinic-*.jar /spring-petclinic.jar
|
|||
CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/spring-petclinic.jar"]
|
||||
```
|
||||
|
||||
We first add a label to the `FROM eclipse-temurin:17-jdk-jammy` statement. This allows us to refer to this build stage in other build stages. Next, we added a new build stage labeled `development`.
|
||||
You first add a label to the `FROM eclipse-temurin:17-jdk-jammy` statement. This allows you to refer to this build stage in other build stages. Next, you added a new build stage labeled `development`.
|
||||
|
||||
We expose port 8000 and declare the debug configuration for the JVM so that we can attach a debugger.
|
||||
You expose port 8000 and declare the debug configuration for the JVM so that you can attach a debugger.
|
||||
|
||||
## Use Compose to develop locally
|
||||
|
||||
We can now create a Compose file to start our development container and the MySQL database using a single command.
|
||||
You can now create a Compose file to start your development container and the MySQL database using a single command.
|
||||
|
||||
Open the `petclinic` in your IDE or a text editor and create a new file named `docker-compose.dev.yml`. Copy and paste the following commands into the file.
|
||||
|
||||
|
@ -159,21 +159,21 @@ volumes:
|
|||
mysql_config:
|
||||
```
|
||||
|
||||
This Compose file is super convenient as we do not have to type all the parameters to pass to the `docker run` command. We can declaratively do that using a Compose file.
|
||||
This Compose file is super convenient as you don't have to type all the parameters to pass to the `docker run` command. You can declaratively do that using a Compose file.
|
||||
|
||||
Another really cool feature of using a Compose file is that we have service resolution set up to use the service names. Therefore, we are now able to use `mysqlserver` in our connection string. The reason we use `mysqlserver` is because that is what we've named our MySQL service as in the Compose file.
|
||||
Another Compose feature is that you have service resolution set up to use the service names. Therefore, you are now able to use `mysqlserver` in your connection string. The reason you use `mysqlserver` is because that's what you've named your MySQL service as in the Compose file.
|
||||
|
||||
Now, to start our application and to confirm that it is running properly.
|
||||
Now, to start your application and to confirm that it's running.
|
||||
|
||||
```console
|
||||
$ docker compose -f docker-compose.dev.yml up --build
|
||||
```
|
||||
|
||||
We pass the `--build` flag so Docker will compile our image and then starts the containers. You should see similar output if it runs successfully:
|
||||
You pass the `--build` flag so Docker will compile your image and then starts the containers. You should see similar output if it runs successfully:
|
||||
|
||||

|
||||
|
||||
Now let’s test our API endpoint. Run the following curl commands:
|
||||
Now, test your API endpoint. Run the following curl command:
|
||||
|
||||
```console
|
||||
$ curl --request GET \
|
||||
|
@ -189,15 +189,15 @@ You should receive the following response:
|
|||
|
||||
## Connect a Debugger
|
||||
|
||||
We’ll use the debugger that comes with the IntelliJ IDEA. You can use the community version of this IDE. Open your project in IntelliJ IDEA and then go to the **Run** menu > **Edit Configuration**. Add a new Remote JVM Debug configuration similar to the following:
|
||||
You’ll use the debugger that comes with the IntelliJ IDEA. You can use the community version of this IDE. Open your project in IntelliJ IDEA, go to the **Run** menu, and then **Edit Configuration**. Add a new Remote JVM Debug configuration similar to the following:
|
||||
|
||||

|
||||
|
||||
Let's set a breakpoint
|
||||
Set a breakpoint.
|
||||
|
||||
Open the following file `src/main/java/org/springframework/samples/petclinic/vet/VetController.java` and add a breakpoint inside the `showResourcesVetList` function.
|
||||
Open `src/main/java/org/springframework/samples/petclinic/vet/VetController.java` and add a breakpoint inside the `showResourcesVetList` function.
|
||||
|
||||
Start your debug session, **Run** menu and then **Debug _NameOfYourConfiguration_**
|
||||
To start your debug session, select the **Run** menu and then **Debug _NameOfYourConfiguration_**.
|
||||
|
||||

|
||||
|
||||
|
@ -205,7 +205,7 @@ You should now see the connection in the logs of your Compose application.
|
|||
|
||||

|
||||
|
||||
We can now call the server endpoint.
|
||||
You can now call the server endpoint.
|
||||
|
||||
```console
|
||||
$ curl --request GET --url http://localhost:8080/vets
|
||||
|
@ -219,12 +219,8 @@ You can also activate the live reload option provided by SpringBoot Dev Tools. C
|
|||
|
||||
## Next steps
|
||||
|
||||
In this module, we took a look at creating a general development image that we can use pretty much like our normal command line. We also set up our Compose file to expose the debugging port and configure Spring Boot to live reload our changes.
|
||||
In this module, you took a look at creating a general development image that you can use pretty much like your normal command line. You also set up your Compose file to expose the debugging port and configure Spring Boot to live reload your changes.
|
||||
|
||||
In the next module, we’ll take a look at how to run unit tests in Docker. See
|
||||
In the next module, you’ll take a look at how to run unit tests in Docker.
|
||||
|
||||
{{< button text="Run your tests" url="run-tests.md" >}}
|
||||
|
||||
## Feedback
|
||||
|
||||
Help us improve this topic by providing your feedback. Let us know what you think by creating an issue in the [Docker Docs]({{% param "repo" %}}/issues/new?title=[Java%20docs%20feedback]) GitHub repository. Alternatively, [create a PR]({{% param "repo" %}}/pulls) to suggest updates.
|
||||
|
|
|
@ -10,17 +10,17 @@ Work through the steps to build a Java image in [Build your Java image](build-im
|
|||
|
||||
## Overview
|
||||
|
||||
In the previous module, we created our sample application and then we created a Dockerfile that we used to build an image. We created our image using the command `docker build`. Now that we have an image, we can run that image and see if our application is running correctly.
|
||||
In the previous module, you created your sample application and then you created a Dockerfile that you used to build an image. You created your image using the command `docker build`. Now that you have an image, you can run that image and see if your application is running correctly.
|
||||
|
||||
A container is a normal operating system process except that this process is isolated and has its own file system, its own networking, and its own isolated process tree separated from the host.
|
||||
|
||||
To run an image inside a container, we use the `docker run` command. The `docker run` command requires one parameter which is the name of the image. Let’s start our image and make sure it is running correctly. Run the following command in your terminal:
|
||||
To run an image inside a container, you use the `docker run` command. The `docker run` command requires one parameter which is the name of the image. Start your image and make sure it's running correctly. Run the following command in your terminal:
|
||||
|
||||
```console
|
||||
$ docker run java-docker
|
||||
```
|
||||
|
||||
After running this command, you’ll notice that we did not return to the command prompt. This is because our application is a REST server and runs in a loop waiting for incoming requests without returning control back to the OS until we stop the container.
|
||||
After running this command, you’ll notice that you didn't return to the command prompt. This is because your application is a REST server and runs in a loop waiting for incoming requests without returning control back to the OS until you stop the container.
|
||||
|
||||
Let’s open a new terminal then make a `GET` request to the server using the `curl` command.
|
||||
|
||||
|
@ -31,11 +31,11 @@ $ curl --request GET \
|
|||
curl: (7) Failed to connect to localhost port 8080: Connection refused
|
||||
```
|
||||
|
||||
As you can see, our `curl` command failed because the connection to our server was refused. It means that we were not able to connect to the localhost on port 8080. This is expected because our container is running in isolation which includes networking. Let’s stop the container and restart with port 8080 published on our local network.
|
||||
As you can see, your `curl` command failed because the connection to your server was refused. It means that you weren't able to connect to the localhost on port 8080. This is expected because your container is running in isolation which includes networking. Stop the container and restart with port 8080 published on your local network.
|
||||
|
||||
To stop the container, press `ctrl-c`. This will return you to the terminal prompt.
|
||||
|
||||
To publish a port for our container, we’ll use the `--publish` flag (`-p` for short) on the `docker run` command. The format of the `--publish` command is `[host port]:[container port]`. So, if we wanted to expose port 8000 inside the container to port 8080 outside the container, we would pass `8080:8000` to the `--publish` flag.
|
||||
To publish a port for your container, you’ll use the `--publish` flag (`-p` for short) on the `docker run` command. The format of the `--publish` command is `[host port]:[container port]`. So, if you wanted to expose port 8000 inside the container to port 8080 outside the container, you would pass `8080:8000` to the `--publish` flag.
|
||||
|
||||
Start the container and expose port 8080 to port 8080 on the host.
|
||||
|
||||
|
@ -43,7 +43,7 @@ Start the container and expose port 8080 to port 8080 on the host.
|
|||
$ docker run --publish 8080:8080 java-docker
|
||||
```
|
||||
|
||||
Now, let’s rerun the curl command from above.
|
||||
Now, rerun the curl command.
|
||||
|
||||
```console
|
||||
$ curl --request GET \
|
||||
|
@ -52,22 +52,22 @@ $ curl --request GET \
|
|||
{"status":"UP"}
|
||||
```
|
||||
|
||||
Success! We were able to connect to the application running inside of our container on port 8080.
|
||||
Success! You were able to connect to the application running inside of your container on port 8080.
|
||||
|
||||
Now, press ctrl-c to stop the container.
|
||||
|
||||
## Run in detached mode
|
||||
|
||||
This is great so far, but our sample application is a web server and we don't have to be connected to the container. Docker can run your container in detached mode or in the background. To do this, we can use the `--detach` or `-d` for short. Docker starts your container as earlier, but this time, it will “detach” from the container and return you to the terminal prompt.
|
||||
This is great so far, but your sample application is a web server and you don't have to be connected to the container. Docker can run your container in detached mode or in the background. To do this, you can use the `--detach` or `-d` for short. Docker starts your container as earlier, but this time, it will “detach” from the container and return you to the terminal prompt.
|
||||
|
||||
```console
|
||||
$ docker run -d -p 8080:8080 java-docker
|
||||
5ff83001608c7b787dbe3885277af018aaac738864d42c4fdf5547369f6ac752
|
||||
```
|
||||
|
||||
Docker started our container in the background and printed the Container ID on the terminal.
|
||||
Docker started your container in the background and printed the Container ID on the terminal.
|
||||
|
||||
Again, let’s make sure that our container is running properly. Run the same curl command from above.
|
||||
Again, make sure that your container is running. Rerun the curl command.
|
||||
|
||||
```console
|
||||
$ curl --request GET \
|
||||
|
@ -78,7 +78,7 @@ $ curl --request GET \
|
|||
|
||||
## List containers
|
||||
|
||||
As we ran our container in the background, how do we know if our container is running, or what other containers are running on our machine? Well, we can run the `docker ps` command. Just like how we run the `ps` command in Linux to see a list of processes on our machine, we can run the `docker ps` command to view a list of containers running on our machine.
|
||||
As you ran your container in the background, how do you know if your container is running, or what other containers are running on your machine? Well, you can run the `docker ps` command. Just like how you run the `ps` command in Linux to see a list of processes on your machine, you can run the `docker ps` command to view a list of containers running on your machine.
|
||||
|
||||
```console
|
||||
$ docker ps
|
||||
|
@ -86,9 +86,9 @@ CONTAINER ID IMAGE COMMAND CREATED ST
|
|||
5ff83001608c java-docker "./mvnw spring-boot:…" About a minute ago Up About a minute 0.0.0.0:8080->8080/tcp trusting_beaver
|
||||
```
|
||||
|
||||
The `docker ps` command provides a bunch of information about our running containers. We can see the container ID, the image running inside the container, the command that was used to start the container, when it was created, the status, ports that exposed and the name of the container.
|
||||
The `docker ps` command provides a bunch of information about your running containers. You can see the container ID, the image running inside the container, the command that was used to start the container, when it was created, the status, ports that exposed and the name of the container.
|
||||
|
||||
You are probably wondering where the name of our container is coming from. Since we didn’t provide a name for the container when we started it, Docker generated a random name. We’ll fix this in a minute, but first we need to stop the container. To stop the container, run the `docker stop` command which does just that, stops the container. We need to pass the name of the container or we can use the container ID.
|
||||
You are probably wondering where the name of your container is coming from. Since you didn’t provide a name for the container when you started it, Docker generated a random name. You'll fix this in a minute, but first you need to stop the container. To stop the container, run the `docker stop` command which does just that, stops the container. You need to pass the name of the container or you can use the container ID.
|
||||
|
||||
```console
|
||||
$ docker stop trusting_beaver
|
||||
|
@ -104,7 +104,7 @@ CONTAINER ID IMAGE COMMAND CREATED
|
|||
|
||||
## Stop, start, and name containers
|
||||
|
||||
You can start, stop, and restart Docker containers. When we stop a container, it is not removed, but the status is changed to stopped and the process inside the container is stopped. When we ran the `docker ps` command in the previous module, the default output only shows running containers. When we pass the `--all` or `-a` for short, we see all containers on our machine, irrespective of their start or stop status.
|
||||
You can start, stop, and restart Docker containers. When you stop a container, it's not removed, but the status is changed to stopped and the process inside the container is stopped. When you ran the `docker ps` command in the previous module, the default output only shows running containers. When you pass the `--all` or `-a` for short, you see all containers on your machine, irrespective of their start or stop status.
|
||||
|
||||
```console
|
||||
$ docker ps -a
|
||||
|
@ -114,9 +114,11 @@ CONTAINER ID IMAGE COMMAND CREATED STA
|
|||
a28f9d587d95 java-docker "./mvnw spring-boot:…" 17 minutes ago Exited (1) 11 minutes ago lucid_greider
|
||||
```
|
||||
|
||||
You should now see several containers listed. These are containers that we started and stopped, but have not been removed.
|
||||
You should now see several containers listed. These are containers that you started and stopped, but haven't been removed.
|
||||
|
||||
Let’s restart the container that we just stopped. Locate the name of the container we just stopped and replace the name of the container below using the `restart` command.
|
||||
Restart the container that you just stopped using the `restart` command. Find
|
||||
the name of your container and replace the name in the following command
|
||||
with the name of the container on your system.
|
||||
|
||||
```console
|
||||
$ docker restart trusting_beaver
|
||||
|
@ -132,16 +134,16 @@ CONTAINER ID IMAGE COMMAND CREATED STATUS
|
|||
a28f9d587d95 java-docker "./mvnw spring-boot:…" 22 minutes ago Exited (1) 16 minutes ago lucid_greider
|
||||
```
|
||||
|
||||
Notice that the container we just restarted has been started in detached mode and has port 8080 exposed. Also, observe the status of the container is “Up X seconds”. When you restart a container, it starts with the same flags or commands that it was originally started with.
|
||||
Notice that the container you just restarted has been started in detached mode and has port 8080 exposed. Also, observe the status of the container is “Up X seconds”. When you restart a container, it starts with the same flags or commands that it was originally started with.
|
||||
|
||||
Now, let’s stop and remove all of our containers and take a look at fixing the random naming issue. Find the name of your running container and replace the name in the command below with the name of the container on your system.
|
||||
Now, stop and remove all of your containers and take a look at fixing the random naming issue. Find the name of your running container and replace the name in the following command with the name of the container on your system.
|
||||
|
||||
```console
|
||||
$ docker stop trusting_beaver
|
||||
trusting_beaver
|
||||
```
|
||||
|
||||
Now that our container is stopped, let’s remove it. When you remove a container, the process inside the container will be stopped and the metadata for the container will be removed.
|
||||
Now that your container is stopped, remove it. When you remove a container, the process inside the container will be stopped and the metadata for the container will be removed.
|
||||
|
||||
To remove a container, simply run the `docker rm` command passing the container name. You can pass multiple container names to the command using a single command. Again, replace the container names in the following command with the container names from your system.
|
||||
|
||||
|
@ -154,9 +156,9 @@ lucid_greider
|
|||
|
||||
Run the `docker ps --all` command again to see that all containers are removed.
|
||||
|
||||
Now, let’s address the random naming issue. The standard practice is to name your containers for the simple reason that it is easier to identify what is running in the container and what application or service it is associated with.
|
||||
Now, you can address the random naming issue. The standard practice is to name your containers for the simple reason that it's easier to identify what's running in the container and what application or service it's associated with.
|
||||
|
||||
To name a container, we just need to pass the `--name` flag to the `docker run` command.
|
||||
To name a container, you just need to pass the `--name` flag to the `docker run` command.
|
||||
|
||||
```console
|
||||
$ docker run --rm -d -p 8080:8080 --name springboot-server java-docker
|
||||
|
@ -166,16 +168,12 @@ CONTAINER ID IMAGE COMMAND CREATED STATUS
|
|||
2e907c68d1c9 java-docker "./mvnw spring-boot:…" 8 seconds ago Up 8 seconds 0.0.0.0:8080->8080/tcp springboot-server
|
||||
```
|
||||
|
||||
That’s better! We can now easily identify our container based on the name.
|
||||
That’s better! You can now easily identify your container based on the name.
|
||||
|
||||
## Next steps
|
||||
|
||||
In this module, we took a look at running containers, publishing ports, and running containers in detached mode. We also took a look at managing containers by starting, stopping, and, restarting them. We also looked at naming our containers so they are more easily identifiable.
|
||||
In this module, you took a look at running containers, publishing ports, and running containers in detached mode. You also took a look at managing containers by starting, stopping, and, restarting them. Finally, you looked at naming your containers so they're more easily identifiable.
|
||||
|
||||
In the next module, we’ll learn how to run a database in a container and connect it to our application. See:
|
||||
In the next module, you'll learn how to run a database in a container and connect it to your application.
|
||||
|
||||
{{< button text="Use containers for development" url="develop.md" >}}
|
||||
|
||||
## Feedback
|
||||
|
||||
Help us improve this topic by providing your feedback. Let us know what you think by creating an issue in the [Docker Docs]({{% param "repo" %}}/issues/new?title=[Java%20docs%20feedback]) GitHub repository. Alternatively, [create a PR]({{% param "repo" %}}/pulls) to suggest updates.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: Run your Java tests
|
||||
keywords: Java, build, test
|
||||
description: How to build and run your Tests
|
||||
description: How to build and run your Java tests
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
@ -10,11 +10,11 @@ Work through the steps to build an image and run it as a containerized applicati
|
|||
|
||||
## Introduction
|
||||
|
||||
Testing is an essential part of modern software development. Testing can mean a lot of things to different development teams. There are unit tests, integration tests and end-to-end testing. In this guide we take a look at running your unit tests in Docker.
|
||||
Testing is an essential part of modern software development. Testing can mean a lot of things to different development teams. There are unit tests, integration tests and end-to-end testing. In this guide you'll take a look at running your unit tests in Docker.
|
||||
|
||||
## Refactor Dockerfile to run tests
|
||||
|
||||
The **Spring Pet Clinic** source code has already tests defined in the test directory `src/test/java/org/springframework/samples/petclinic`. We can use the following Docker command to start the container and run tests:
|
||||
The **Spring Pet Clinic** source code has already tests defined in the test directory `src/test/java/org/springframework/samples/petclinic`. You can use the following Docker command to start the container and run tests:
|
||||
|
||||
```console
|
||||
$ docker run -it --rm --name springboot-test java-docker ./mvnw test
|
||||
|
@ -31,7 +31,7 @@ $ docker run -it --rm --name springboot-test java-docker ./mvnw test
|
|||
|
||||
### Multi-stage Dockerfile for testing
|
||||
|
||||
Let’s take a look at pulling the testing commands into our Dockerfile. Below is our updated multi-stage Dockerfile that we will use to build our test image. Replace the contents of your Dockerfile with the following.
|
||||
Now, you'll learn how to pull the testing commands into your Dockerfile. The following is your updated multi-stage Dockerfile that you'll use to build your test image. Replace the contents of your Dockerfile with the following.
|
||||
|
||||
```dockerfile
|
||||
# syntax=docker/dockerfile:1
|
||||
|
@ -59,9 +59,9 @@ COPY --from=build /app/target/spring-petclinic-*.jar /spring-petclinic.jar
|
|||
CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/spring-petclinic.jar"]
|
||||
```
|
||||
|
||||
We added a new build stage labeled `test`. We'll use this stage for running our tests.
|
||||
You added a new build stage labeled `test`. You'll use this stage for running your tests.
|
||||
|
||||
Now let’s rebuild our image and run our tests. We will run the `docker build` command as above, but this time we will add the `--target test` flag so that we specifically run the test build stage.
|
||||
Now, rebuild your image and run your tests. You'll run the `docker build` command like you did previously, but this time you'll add the `--target test` flag so that you specifically run the test build stage.
|
||||
|
||||
```console
|
||||
$ docker build -t java-docker --target test .
|
||||
|
@ -71,7 +71,7 @@ $ docker build -t java-docker --target test .
|
|||
=> => naming to docker.io/library/java-docker
|
||||
```
|
||||
|
||||
Now that our test image is built, we can run it as a container and see if our tests pass.
|
||||
Now that your test image is built, you can run it as a container and see if your tests pass.
|
||||
|
||||
```console
|
||||
$ docker run -it --rm --name springboot-test java-docker
|
||||
|
@ -91,9 +91,9 @@ $ docker run -it --rm --name springboot-test java-docker
|
|||
[INFO] Total time: 01:22 min
|
||||
```
|
||||
|
||||
The build output is truncated, but you can see that the Maven test runner was successful and all our tests passed.
|
||||
The build output is truncated, but you can see that the Maven test runner was successful and all your tests passed.
|
||||
|
||||
This is great. However, we'll have to run two Docker commands to build and run our tests. We can improve this slightly by using a `RUN` statement instead of the `CMD` statement in the test stage. The `CMD` statement is not executed during the building of the image, but is executed when you run the image in a container. When using the `RUN` statement, our tests run when building the image, and stop the build when they fail.
|
||||
This is great. However, you'll have to run two Docker commands to build and run your tests. You can improve this slightly by using a `RUN` statement instead of the `CMD` statement in the test stage. The `CMD` statement isn't executed during the building of the image, but is executed when you run the image in a container. When using the `RUN` statement, your tests run when building the image, and stop the build when they fail.
|
||||
|
||||
Update your Dockerfile with the following.
|
||||
|
||||
|
@ -122,7 +122,7 @@ COPY --from=build /app/target/spring-petclinic-*.jar /spring-petclinic.jar
|
|||
CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/spring-petclinic.jar"]
|
||||
```
|
||||
|
||||
Now, to run our tests, we just need to run the `docker build` command as above.
|
||||
Now, to run your tests, you just need to run the `docker build` command.
|
||||
|
||||
```console
|
||||
$ docker build -t java-docker --target test .
|
||||
|
@ -138,21 +138,16 @@ $ docker build -t java-docker --target test .
|
|||
=> => naming to docker.io/library/java-docker
|
||||
```
|
||||
|
||||
The build output is truncated for simplicity, but you can see that our tests ran successfully and passed. Let’s break one of the tests and observe the output when our tests fail.
|
||||
The build output is truncated for simplicity, but you can see that your tests ran successfully and passed. Look at one of the tests and observe the output when your tests fail.
|
||||
|
||||
Open the `src/test/java/org/springframework/samples/petclinic/model/ValidatorTests.java` file and change the assertion
|
||||
Open the `src/test/java/org/springframework/samples/petclinic/model/ValidatorTests.java` file and change the following assertion.
|
||||
|
||||
```java
|
||||
assertThat(violation.getMessage()).isEqualTo("must not be empty");
|
||||
```diff
|
||||
- assertThat(violation.getMessage()).isEqualTo("must not be empty");
|
||||
+ assertThat(violation.getMessage()).isEqualTo("must be empty");
|
||||
```
|
||||
|
||||
with the following.
|
||||
|
||||
```java
|
||||
assertThat(violation.getMessage()).isEqualTo("must be empty");
|
||||
```
|
||||
|
||||
Now, run the `docker build` command from above and observe that the build fails and the failing testing information is printed to the console.
|
||||
Now, run the `docker build` command and observe that the build fails and the failing testing information is printed to the console.
|
||||
|
||||
```console
|
||||
$ docker build -t java-docker --target test .
|
||||
|
@ -165,12 +160,8 @@ executor failed running [./mvnw test]: exit code: 1
|
|||
|
||||
## Next steps
|
||||
|
||||
In this module, we took a look at running tests as part of our Docker image build process.
|
||||
In this module, you took a look at running tests as part of your Docker image build process.
|
||||
|
||||
In the next module, we’ll take a look at how to set up a CI/CD pipeline using GitHub Actions. See:
|
||||
In the next module, you’ll take a look at how to set up a CI/CD pipeline using GitHub Actions.
|
||||
|
||||
{{< button text="Configure CI/CD" url="configure-ci-cd.md" >}}
|
||||
|
||||
## Feedback
|
||||
|
||||
Help us improve this topic by providing your feedback. Let us know what you think by creating an issue in the [Docker Docs]({{% param "repo" %}}/issues/new?title=[Java%20docs%20feedback]) GitHub repository. Alternatively, [create a PR]({{% param "repo" %}}/pulls) to suggest updates.
|
||||
|
|
Loading…
Reference in New Issue