Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 0d48ebd

Browse files
authoredDec 6, 2024
Merge pull request #195 from cisagov/improvement/update_Dockerfile_configuration
Update Dockerfile configuration
2 parents 7d4071d + fd69f45 commit 0d48ebd

File tree

8 files changed

+171
-71
lines changed

8 files changed

+171
-71
lines changed
 

‎.github/workflows/build.yml

-4
Original file line numberDiff line numberDiff line change
@@ -348,8 +348,6 @@ jobs:
348348
id: docker_build
349349
uses: docker/build-push-action@v6
350350
with:
351-
build-args: |
352-
VERSION=${{ needs.prepare.outputs.source_version }}
353351
cache-from: type=local,src=${{ env.BUILDX_CACHE_DIR }}
354352
cache-to: type=local,dest=${{ env.BUILDX_CACHE_DIR }}
355353
context: .
@@ -516,8 +514,6 @@ jobs:
516514
id: docker_build
517515
uses: docker/build-push-action@v6
518516
with:
519-
build-args: |
520-
VERSION=${{ needs.prepare.outputs.source_version }}
521517
cache-from: type=local,src=${{ env.BUILDX_CACHE_DIR }}
522518
cache-to: type=local,dest=${{ env.BUILDX_CACHE_DIR }}
523519
context: .

‎Dockerfile

+67-51
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,59 @@
1-
ARG VERSION=unspecified
1+
# Official Docker images are in the form library/<app> while non-official
2+
# images are in the form <user>/<app>.
3+
FROM docker.io/library/python:3.13.1-alpine3.20 AS compile-stage
24

3-
FROM python:3.12.0-alpine
5+
###
6+
# Unprivileged user variables
7+
###
8+
ARG CISA_USER="cisa"
9+
ENV CISA_HOME="/home/${CISA_USER}"
10+
ENV VIRTUAL_ENV="${CISA_HOME}/.venv"
411

5-
ARG VERSION
12+
# Versions of the Python packages installed directly
13+
ENV PYTHON_PIP_VERSION=24.3.1
14+
ENV PYTHON_PIPENV_VERSION=2024.4.0
15+
ENV PYTHON_SETUPTOOLS_VERSION=75.6.0
16+
ENV PYTHON_WHEEL_VERSION=0.45.1
17+
18+
###
19+
# Install the specified versions of pip, setuptools, and wheel into the system
20+
# Python environment; install the specified version of pipenv into the system Python
21+
# environment; set up a Python virtual environment (venv); and install the specified
22+
# versions of pip, setuptools, and wheel into the venv.
23+
#
24+
# Note that we use the --no-cache-dir flag to avoid writing to a local
25+
# cache. This results in a smaller final image, at the cost of
26+
# slightly longer install times.
27+
###
28+
RUN python3 -m pip install --no-cache-dir --upgrade \
29+
pip==${PYTHON_PIP_VERSION} \
30+
setuptools==${PYTHON_SETUPTOOLS_VERSION} \
31+
wheel==${PYTHON_WHEEL_VERSION} \
32+
&& python3 -m pip install --no-cache-dir --upgrade \
33+
pipenv==${PYTHON_PIPENV_VERSION} \
34+
# Manually create the virtual environment
35+
&& python3 -m venv ${VIRTUAL_ENV} \
36+
# Ensure the core Python packages are installed in the virtual environment
37+
&& ${VIRTUAL_ENV}/bin/python3 -m pip install --no-cache-dir --upgrade \
38+
pip==${PYTHON_PIP_VERSION} \
39+
setuptools==${PYTHON_SETUPTOOLS_VERSION} \
40+
wheel==${PYTHON_WHEEL_VERSION}
41+
42+
###
43+
# Check the Pipfile configuration and then install the Python dependencies into
44+
# the virtual environment.
45+
#
46+
# Note that pipenv will install into a virtual environment if the VIRTUAL_ENV
47+
# environment variable is set.
48+
###
49+
WORKDIR /tmp
50+
COPY src/Pipfile src/Pipfile.lock ./
51+
RUN pipenv check --verbose \
52+
&& pipenv install --clear --deploy --extra-pip-args "--no-cache-dir" --verbose
53+
54+
# Official Docker images are in the form library/<app> while non-official
55+
# images are in the form <user>/<app>.
56+
FROM docker.io/library/python:3.13.1-alpine3.20 AS build-stage
657

758
###
859
# For a list of pre-defined annotation keys and value types see:
@@ -27,15 +78,7 @@ ARG CISA_GID=${CISA_UID}
2778
ARG CISA_USER="cisa"
2879
ENV CISA_GROUP=${CISA_USER}
2980
ENV CISA_HOME="/home/${CISA_USER}"
30-
31-
###
32-
# Upgrade the system
33-
#
34-
# Note that we use apk --no-cache to avoid writing to a local cache.
35-
# This results in a smaller final image, at the cost of slightly
36-
# longer install times.
37-
###
38-
RUN apk --update --no-cache --quiet upgrade
81+
ENV VIRTUAL_ENV="${CISA_HOME}/.venv"
3982

4083
###
4184
# Create unprivileged user
@@ -44,52 +87,25 @@ RUN addgroup --system --gid ${CISA_GID} ${CISA_GROUP} \
4487
&& adduser --system --uid ${CISA_UID} --ingroup ${CISA_GROUP} ${CISA_USER}
4588

4689
###
47-
# Dependencies
90+
# Copy in the Python virtual environment created in compile-stage, symlink the
91+
# Python binary in the venv to the system-wide Python, and add the venv to the PATH.
4892
#
49-
# Note that we use apk --no-cache to avoid writing to a local cache.
50-
# This results in a smaller final image, at the cost of slightly
51-
# longer install times.
52-
###
53-
ENV DEPS \
54-
ca-certificates \
55-
openssl \
56-
py-pip
57-
RUN apk --no-cache --quiet add ${DEPS}
58-
59-
###
60-
# Make sure pip, setuptools, and wheel are the latest versions
61-
#
62-
# Note that we use pip3 --no-cache-dir to avoid writing to a local
63-
# cache. This results in a smaller final image, at the cost of
64-
# slightly longer install times.
65-
###
66-
RUN pip3 install --no-cache-dir --upgrade \
67-
pip \
68-
setuptools \
69-
wheel
70-
71-
WORKDIR ${CISA_HOME}
72-
73-
###
74-
# Install Python dependencies
75-
#
76-
# Note that we use pip3 --no-cache-dir to avoid writing to a local
77-
# cache. This results in a smaller final image, at the cost of
78-
# slightly longer install times.
79-
###
80-
RUN wget --output-document sourcecode.tgz \
81-
https://github.com/cisagov/skeleton-python-library/archive/v${VERSION}.tar.gz \
82-
&& tar --extract --gzip --file sourcecode.tgz --strip-components=1 \
83-
&& pip3 install --no-cache-dir --requirement requirements.txt \
84-
&& ln -snf /run/secrets/quote.txt src/example/data/secret.txt \
85-
&& rm sourcecode.tgz
93+
# Note that we symlink the Python binary in the venv to the system-wide Python so that
94+
# any calls to `python3` will use our virtual environment. We are using short flags
95+
# because the ln binary in Alpine Linux does not support long flags. The -f instructs
96+
# ln to remove the existing file and the -s instructs ln to create a symbolic link.
97+
###
98+
COPY --from=compile-stage --chown=${CISA_USER}:${CISA_GROUP} ${VIRTUAL_ENV} ${VIRTUAL_ENV}
99+
RUN ln -fs "$(command -v python3)" "${VIRTUAL_ENV}"/bin/python3
100+
ENV PATH="${VIRTUAL_ENV}/bin:$PATH"
86101

87102
###
88103
# Prepare to run
89104
###
90105
ENV ECHO_MESSAGE="Hello World from Dockerfile"
106+
WORKDIR ${CISA_HOME}
91107
USER ${CISA_USER}:${CISA_GROUP}
92108
EXPOSE 8080/TCP
93109
VOLUME ["/var/log"]
94110
ENTRYPOINT ["example"]
95-
CMD ["--log-level", "DEBUG"]
111+
CMD ["--log-level", "DEBUG", "8", "2"]

‎README.md

+41-12
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ appropriate for Docker containers and the major languages that we use.
2424
To run the `cisagov/example` image via Docker:
2525

2626
```console
27-
docker run cisagov/example:0.0.1
27+
docker run cisagov/example:0.2.0
2828
```
2929

3030
### Running with Docker Compose ###
@@ -37,7 +37,7 @@ docker run cisagov/example:0.0.1
3737

3838
services:
3939
example:
40-
image: cisagov/example:0.0.1
40+
image: cisagov/example:0.2.0
4141
volumes:
4242
- type: bind
4343
source: <your_log_dir>
@@ -82,7 +82,7 @@ environment variables. See the
8282
8383
services:
8484
example:
85-
image: cisagov/example:0.0.1
85+
image: cisagov/example:0.2.0
8686
volumes:
8787
- type: bind
8888
source: <your_log_dir>
@@ -125,23 +125,52 @@ environment variables. See the
125125
1. Pull the new image:
126126

127127
```console
128-
docker pull cisagov/example:0.0.1
128+
docker pull cisagov/example:0.2.0
129129
```
130130

131131
1. Recreate and run the container by following the [previous instructions](#running-with-docker).
132132

133+
## Updating Python dependencies ##
134+
135+
This image uses [Pipenv] to manage Python dependencies using a [Pipfile](https://github.com/pypa/pipfile).
136+
Both updating dependencies and changing the [Pipenv] configuration in `src/Pipfile`
137+
will result in a modified `src/Pipfile.lock` file that should be committed to the
138+
repository.
139+
140+
> [!WARNING]
141+
> The `src/Pipfile.lock` as generated will fail `pre-commit` checks due to JSON formatting.
142+
143+
### Updating dependencies ###
144+
145+
If you want to update existing dependencies you would run the following command
146+
in the `src/` subdirectory:
147+
148+
```console
149+
pipenv lock
150+
```
151+
152+
### Modifying dependencies ###
153+
154+
If you want to add or remove dependencies you would update the `src/Pipfile` file
155+
and then update dependencies as you would above.
156+
157+
> [!NOTE]
158+
> You should only specify packages that are explicitly needed for your Docker
159+
> configuration. Allow [Pipenv] to manage the dependencies of the specified
160+
> packages.
161+
133162
## Image tags ##
134163

135164
The images of this container are tagged with [semantic
136165
versions](https://semver.org) of the underlying example project that they
137166
containerize. It is recommended that most users use a version tag (e.g.
138-
`:0.0.1`).
167+
`:0.2.0`).
139168

140169
| Image:tag | Description |
141170
|-----------|-------------|
142-
|`cisagov/example:1.2.3`| An exact release version. |
143-
|`cisagov/example:1.2`| The most recent release matching the major and minor version numbers. |
144-
|`cisagov/example:1`| The most recent release matching the major version number. |
171+
|`cisagov/example:0.2.0`| An exact release version. |
172+
|`cisagov/example:0.2`| The most recent release matching the major and minor version numbers. |
173+
|`cisagov/example:0`| The most recent release matching the major version number. |
145174
|`cisagov/example:edge` | The most recent image built from a merge into the `develop` branch of this repository. |
146175
|`cisagov/example:nightly` | A nightly build of the `develop` branch of this repository. |
147176
|`cisagov/example:latest`| The most recent release image pushed to a container registry. Pulling an image using the `:latest` tag [should be avoided.](https://vsupalov.com/docker-latest-tag/) |
@@ -196,8 +225,7 @@ Build the image locally using this git repository as the [build context](https:/
196225

197226
```console
198227
docker build \
199-
--build-arg VERSION=0.0.1 \
200-
--tag cisagov/example:0.0.1 \
228+
--tag cisagov/example:0.2.0 \
201229
https://github.com/cisagov/example.git#develop
202230
```
203231

@@ -227,9 +255,8 @@ Docker:
227255
docker buildx build \
228256
--file Dockerfile-x \
229257
--platform linux/amd64 \
230-
--build-arg VERSION=0.0.1 \
231258
--output type=docker \
232-
--tag cisagov/example:0.0.1 .
259+
--tag cisagov/example:0.2.0 .
233260
```
234261

235262
## New repositories from a skeleton ##
@@ -256,3 +283,5 @@ dedication](https://creativecommons.org/publicdomain/zero/1.0/).
256283
All contributions to this project will be released under the CC0
257284
dedication. By submitting a pull request, you are agreeing to comply
258285
with this waiver of copyright interest.
286+
287+
[Pipenv]: https://pypi.org/project/pipenv/

‎requirements-dev.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
--requirement requirements-test.txt
22
ipython
3+
pipenv
34
semver>=3

‎src/Pipfile

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[[source]]
2+
url = "https://pypi.org/simple"
3+
verify_ssl = true
4+
name = "pypi"
5+
6+
# List any Python dependencies for the image here
7+
[packages]
8+
# This should match the version of the image
9+
example = {file = "https://github.com/cisagov/skeleton-python-library/archive/v0.2.0.tar.gz"}
10+
11+
# This version should match the version of Python in the image
12+
[requires]
13+
python_full_version = "3.13.1"

‎src/Pipfile.lock

+45
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/version.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.0.1
1+
0.2.0

‎tests/container_test.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@
1010
ENV_VAR = "ECHO_MESSAGE"
1111
ENV_VAR_VAL = "Hello World from docker compose!"
1212
READY_MESSAGE = "This is a debug message"
13-
SECRET_QUOTE = (
14-
"There are no secrets better kept than the secrets everybody guesses." # nosec
15-
)
13+
DIVISION_MESSAGE = "8 / 2 == 4.000000"
14+
SECRET_QUOTE = "Three may keep a secret, if two of them are dead." # nosec
1615
RELEASE_TAG = os.getenv("RELEASE_TAG")
1716
VERSION_FILE = "src/version.txt"
1817

@@ -54,6 +53,7 @@ def test_output(dockerc, main_container):
5453
# make sure container exited if running test isolated
5554
dockerc.wait(main_container.id)
5655
log_output = main_container.logs()
56+
assert DIVISION_MESSAGE in log_output, "Division message not found in log output."
5757
assert SECRET_QUOTE in log_output, "Secret not found in log output."
5858

5959

0 commit comments

Comments
 (0)
Please sign in to comment.