You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/developer-guides/Scripting_Docker.md
+89-25Lines changed: 89 additions & 25 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -23,10 +23,13 @@ author: Ross Buggins
23
23
-[Versioning](#versioning)
24
24
-[Variables](#variables)
25
25
-[Platform architecture](#platform-architecture)
26
+
-[`Dockerignore` file](#dockerignore-file)
26
27
-[FAQ](#faq)
27
28
28
29
## Overview
29
30
31
+
This document provides instructions on how to build Docker images using our automated build process. You'll learn how to specify version tags, commit changes, and understand the build output.
32
+
30
33
Docker is a tool for developing, shipping and running applications inside containers for Serverless and Kubernetes-based workloads. It has grown in popularity due to its ability to address several challenges faced by engineers, like:
31
34
32
35
-**Consistency across environments**: One of the common challenges in software development is the "it works on my machine" problem. Docker containers ensure that applications run the same regardless of where the container is run, be it a developer's local machine, a test environment or a production server.
@@ -55,7 +58,6 @@ Here are some key features built into this repository's Docker module:
55
58
- Incorporates metadata through `Dockerfile` labels for enhanced documentation and to conform to standards
56
59
- Integrates a linting routine to ensure `Dockerfile` code quality
57
60
- Includes an automated test suite to validate Docker scripts
58
-
- Provides a ready-to-run example to demonstrate the module's functionality
59
61
- Incorporates a best practice guide
60
62
61
63
## Key files
@@ -73,50 +75,108 @@ Here are some key features built into this repository's Docker module:
73
75
-[`docker.test.sh`](../../scripts/docker/tests/docker.test.sh): Main file containing all the tests
74
76
-[`Dockerfile`](../../scripts/docker/tests/Dockerfile): Image definition for the test suite
75
77
-[`VERSION`](../../scripts/docker/tests/VERSION): Version patterns for the test suite
76
-
- Usage example
77
-
- Python-based example [`hello_world`](../../scripts/docker/examples/python) app showing a multi-staged build
78
-
- A set of [make targets](https://github.com/nhs-england-tools/repository-template/blob/main/scripts/docker/docker.mk#L18) to run the example
79
78
80
79
## Usage
81
80
82
81
### Quick start
83
82
84
-
Run the test suite:
83
+
The Repository Template assumes that you will want to build more than one docker image as part of your project. As such, we do not use a `Dockerfile` at the root of the project. Instead, each docker image that you create should go in its own folder under `infrastructure/images`. So, if your application has a docker image called `my-shiny-app`, you should create the file `infrastructure/images/my-shiny-app/Dockerfile`. Let's do that.
84
+
85
+
First, we need an application to package. Let's do the simplest possible thing, and create a file called `main.py` in the root of the template with a familiar command in it:
86
+
87
+
```python
88
+
print("hello world")
89
+
```
90
+
91
+
Run this command to make the directory:
92
+
93
+
```shell
94
+
mkdir -p infrastructure/images/my-shiny-app
95
+
```
96
+
97
+
Now, edit `infrastructure/images/my-shiny-app/Dockerfile` and put this into it:
98
+
99
+
```dockerfile
100
+
FROM python
101
+
102
+
COPY ./main.py .
103
+
104
+
CMD ["python", "main.py"]
105
+
```
106
+
107
+
Note the paths in the `COPY` command. The `Dockerfile` is stored in a subdirectory, but when `docker` runs it is executed in the root of the repository so that's where all paths are relative to. This is because you can't `COPY` from parent directories. `COPY ../../main.py .` wouldn't work.
108
+
109
+
The name of the folder is also significant. It should match the name of the docker image that you want to create. With that name, you can run the following `make` task to run `hadolint` over your `Dockerfile` to check for common anti-patterns:
110
+
111
+
```shell
112
+
$ DOCKER_IMAGE=my-shiny-app make docker-lint
113
+
/workdir/./infrastructure/images/my-shiny-app/Dockerfile.effective:1 DL3006 warning: Always tag the version of an image explicitly
All the provided docker `make` tasks take the `DOCKER_IMAGE` parameter.
119
+
120
+
`hadolint` found a problem, so let's fix that. It's complaining that we've not specified which version of the `python` docker container we want. Change the first line of the `Dockerfile` to:
121
+
122
+
```dockerfile
123
+
FROM python:3.12-slim-bookworm
124
+
```
125
+
126
+
Run `DOCKER_IMAGE=my-shiny-app make docker-lint` again, and you will see that it is silent.
127
+
128
+
Now let's actually build the image. Run the following:
129
+
130
+
```shell
131
+
DOCKER_IMAGE=my-shiny-app make docker-build
132
+
```
133
+
134
+
And now we can run it:
135
+
136
+
```shell
137
+
$ DOCKER_IMAGE=my-shiny-app make docker-run
138
+
hello world
139
+
```
140
+
141
+
If you list your images, you'll see that the image name matches the directory name under `infrastructure/images`:
85
142
86
143
```shell
87
-
$ make docker-test-suite-run
144
+
$ docker image ls
145
+
REPOSITORY TAG IMAGE ID CREATED SIZE
146
+
localhost/my-shiny-app latest 6a0adeb5348c 2 hours ago 135 MB
147
+
docker.io/library/python 3.12-slim-bookworm d9f1825e4d49 5 weeks ago 135 MB
148
+
localhost/hadolint/hadolint 2.12.0-alpine 19b38dcec411 16 months ago 8.3 MB
149
+
```
88
150
89
-
test-docker-build PASS
90
-
test-docker-test PASS
91
-
test-docker-run PASS
92
-
test-docker-clean PASS
151
+
Your process might want to add specific tag formats so you can identify docker images by date-stamps, or git hashes. The Repository Template supports that with a `VERSION` file. Create a new file called `infrastructure/images/my-shiny-app/VERSION`, and put the following into it:
152
+
153
+
```text
154
+
${yyyy}${mm}${dd}-${hash}
93
155
```
94
156
95
-
Run the example:
157
+
Now, run the `docker-build` command again, and towards the end of the output you will see something that looks like this:
#0 building with "desktop-linux" instance using docker driver
101
-
...
102
-
#12 DONE 0.0s
163
+
Obviously the specific values will be different for you. See the Versioning section below for more on this.
103
164
104
-
$ make docker-example-run
165
+
It is usually the case that there is a specific image that you will most often want to build, run, and deploy. You should edit the root-level `Makefile` to document this and to provide shortcuts. Edit `Makefile`, and change the `build` task to look like this:
105
166
106
-
* Serving Flask app 'app'
107
-
* Debug mode: off
108
-
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
109
-
* Running on all addresses (0.0.0.0)
110
-
* Running on http://127.0.0.1:8000
111
-
* Running on http://172.17.0.2:8000
112
-
Press CTRL+C to quit
167
+
```make
168
+
build: # Build the project artefact @Pipeline
169
+
DOCKER_IMAGE=my-shiny-app
170
+
make docker-build
113
171
```
114
172
173
+
Now when you run `make build`, it will do the right thing. Keeping this convention consistent across projects means that new starters can be on-boarded quickly, without needing to learn a new set of conventions each time.
174
+
115
175
### Your image implementation
116
176
117
-
Always follow [Docker best practices](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/) while developing images. Start with creating your container definition for the service and store it in the `infrastructure/images` directory.
177
+
Alwaysfollow[Dockerbestpractices](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/) while developing images.
118
178
119
-
Here is a step-by-step guide:
179
+
Here is a step-by-step guide for an image which packages a third-party tool. It is mostly similar to the example above, but demonstrates the `.tool-versions` mechanism.
@@ -224,6 +284,10 @@ Set the `docker_image` or `DOCKER_IMAGE` variable for your image. Alternatively,
224
284
225
285
For cross-platform image support, the `--platform linux/amd64` flag is used to build Docker images, enabling containers to run without any changes on both `amd64` and `arm64` architectures (via emulation).
226
286
287
+
### `Dockerignore` file
288
+
289
+
If you need to exclude files from a `COPY` command, put a [`Dockerfile.dockerignore`](https://docs.docker.com/build/building/context/#filename-and-location) file next to the relevant `Dockerfile`. They do not live in the root directory. Any paths within `Dockerfile.dockerignore` must be relative to the repository root.
290
+
227
291
## FAQ
228
292
229
293
1._We built our serverless workloads based on AWS Lambda and package them as `.zip` archives. Why do we need Docker?_
0 commit comments