Skip to content

Commit 7f68f49

Browse files
bryanlattenBryan Latten
andauthored
Dockerfile: updated bases to 4.0 (#78)
* Dockerfile: updated bases to 4.0 * Github actions: replace Hub build with multi-arch * Traivs: multi-arch, GH action CI * CI: separated out publish from PR action * CI: localhost port publishing networking * CI: working action and documentation * CI: work around mounted docker sockets * Review: tweaks * Dockerfile: consolidated woff fixes, ubuntu + cent * Dockerfile-centos: upgrading nginx, TLS 1.3 support * README: X64 warning * Woff: newline for @bossjones Co-authored-by: Bryan Latten <[email protected]>
1 parent 41248ef commit 7f68f49

File tree

10 files changed

+237
-12
lines changed

10 files changed

+237
-12
lines changed

.github/workflows/ci.yml

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
name: ci
2+
3+
on:
4+
pull_request:
5+
branches: [ master ]
6+
7+
jobs:
8+
test:
9+
runs-on: ubuntu-latest
10+
strategy:
11+
matrix:
12+
props:
13+
- Dockerfile: Dockerfile
14+
- Dockerfile: Dockerfile-alpine
15+
- Dockerfile: Dockerfile-centos
16+
platform:
17+
- linux/amd64
18+
- linux/arm64
19+
env:
20+
TEST_MATCH: Welcome to nginx!
21+
steps:
22+
-
23+
name: Checkout
24+
uses: actions/checkout@v2
25+
-
26+
name: Detect host configuration
27+
run: |
28+
# NOTE: Docker host configuration determines the networking target for integration testing
29+
v=$(mount | grep "/run/docker.sock")
30+
TARGET_HOST=
31+
32+
if [ -n "$v" ]; then
33+
echo "Injected docker socket detected"
34+
TARGET_HOST="host.docker.internal"
35+
elif [ -S /var/run/docker.sock ]; then
36+
TARGET_HOST="localhost"
37+
else
38+
echo "No Docker socket detected, fail"
39+
exit 1
40+
fi
41+
echo "TARGET_HOST=${TARGET_HOST}" >> $GITHUB_ENV
42+
-
43+
# Build and execute in multiple configurations: vanilla, with env overrides, with TLS enabled
44+
name: Build and test
45+
run: |
46+
# NOTE: docker qemu and buildx setup actions create a black hole for build cache layers, avoid unless pushing externally
47+
# Setup multi-arch platforms, noop if already installed for builder
48+
docker run --privileged --rm tonistiigi/binfmt --install arm64,amd64
49+
50+
TARGET_PLATFORM=${{ matrix.platform }}
51+
TARGET_DOCKERFILE=${{ matrix.props.Dockerfile }}
52+
53+
# Since containers may or may not be against the same docker engine, create a matrix-unique tag name for outputs
54+
TAG_NAME="docker-nginx-${TARGET_DOCKERFILE}-${TARGET_PLATFORM}"
55+
# Formats as lowercase
56+
TAG_NAME=$(echo $TAG_NAME | tr '[:upper:]' '[:lower:]')
57+
# Removes slashes
58+
TAG_NAME=$(echo $TAG_NAME | sed 's/\///')
59+
60+
echo $TAG_NAME
61+
62+
docker buildx build --platform $TARGET_PLATFORM --iidfile $TAG_NAME -t $TAG_NAME -f $TARGET_DOCKERFILE .
63+
64+
# NOTE: multi-arch builds may not be accessible by docker tag, instead target by ID
65+
BUILD_SHA=$(cat ./$TAG_NAME)
66+
67+
# Remove sha256: from tag identifier
68+
BUILD_SHA=$(echo $BUILD_SHA | sed 's/sha256\://')
69+
70+
# Generate self-signed certificates
71+
mkdir -p certs
72+
openssl genrsa -out ./certs/ca.key 2048
73+
openssl req -new -key ./certs/ca.key -out ./certs/ca.csr -subj '/CN=localhost'
74+
openssl x509 -req -days 365 -in ./certs/ca.csr -signkey ./certs/ca.key -out ./certs/ca.crt
75+
76+
# Run various configurations of containers
77+
CONTAINER_VANILLA=$(docker run --platform $TARGET_PLATFORM --rm -p 8080 -d $BUILD_SHA)
78+
CONTAINER_ENV_FILE=$(docker run --platform $TARGET_PLATFORM --rm -p 8080 -d --env-file ./.test.env $BUILD_SHA)
79+
CONTAINER_HTTPS=$(docker run --platform $TARGET_PLATFORM --rm -p 8080 -d -e SERVER_ENABLE_HTTPS=true -v $(pwd)/certs:/etc/nginx/certs:ro $BUILD_SHA)
80+
81+
# Retrieve dynamically-allocated host port
82+
VANILLA_PORT=$(docker inspect --format '{{ (index (index .NetworkSettings.Ports "8080/tcp") 0).HostPort }}' $CONTAINER_VANILLA)
83+
ENV_FILE_PORT=$(docker inspect --format '{{ (index (index .NetworkSettings.Ports "8080/tcp") 0).HostPort }}' $CONTAINER_ENV_FILE)
84+
HTTPS_PORT=$(docker inspect --format '{{ (index (index .NetworkSettings.Ports "8080/tcp") 0).HostPort }}' $CONTAINER_HTTPS)
85+
86+
# Wait for containers to boot (in background)
87+
sleep 5
88+
89+
TARGET_HOST=${{ env.TARGET_HOST }}
90+
echo "HOSTING ${TARGET_HOST}"
91+
92+
# Check for nginx test page response
93+
curl ${TARGET_HOST}:${VANILLA_PORT} | grep "${{ env.TEST_MATCH }}"
94+
curl ${TARGET_HOST}:${ENV_FILE_PORT} | grep "${{ env.TEST_MATCH }}"
95+
curl -k https://${TARGET_HOST}:${HTTPS_PORT} | grep "${{ env.TEST_MATCH }}"
96+
97+
# Cleanup
98+
docker kill $CONTAINER_VANILLA
99+
docker kill $CONTAINER_ENV_FILE
100+
docker kill $CONTAINER_HTTPS
101+
docker rmi $BUILD_SHA

.github/workflows/publish.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: publish
2+
3+
on:
4+
push:
5+
tags:
6+
- '*'
7+
8+
jobs:
9+
publish:
10+
runs-on: ubuntu-latest
11+
env:
12+
IMAGE_BASE: behance/docker-nginx
13+
strategy:
14+
matrix:
15+
props:
16+
# This is the default variant-less distribution (ex. 3.2.1)
17+
- Dockerfile: Dockerfile
18+
# Variant distributions below all have semantic versions + suffix (ex. 3.2.1-alpine)
19+
- Dockerfile: Dockerfile-alpine
20+
suffix: alpine
21+
- Dockerfile: Dockerfile-centos
22+
suffix: centos
23+
steps:
24+
-
25+
name: Checkout
26+
uses: actions/checkout@v2
27+
-
28+
name: Add tag suffix
29+
if: matrix.props.suffix
30+
run: |
31+
echo TAG_SUFFIX="-${{ matrix.props.suffix }}" >> $GITHUB_ENV
32+
-
33+
name: Docker meta
34+
id: meta
35+
if: github.event_name != 'pull_request'
36+
uses: docker/metadata-action@v3
37+
with:
38+
images: ${{ env.IMAGE_BASE }}
39+
tags: |
40+
type=semver,pattern={{major}}.{{minor}}.{{patch}}
41+
type=semver,pattern={{major}}.{{minor}}
42+
type=semver,pattern={{major}}
43+
flavor: |
44+
latest=auto
45+
suffix=${{ env.TAG_SUFFIX }}
46+
-
47+
name: Set up QEMU
48+
uses: docker/setup-qemu-action@v1
49+
-
50+
name: Set up Docker Buildx
51+
uses: docker/setup-buildx-action@v1
52+
-
53+
name: Login to DockerHub
54+
if: github.event_name != 'pull_request'
55+
uses: docker/login-action@v1
56+
with:
57+
username: ${{ secrets.DOCKERHUB_USERNAME }}
58+
password: ${{ secrets.DOCKERHUB_TOKEN }}
59+
-
60+
name: Build + push
61+
uses: docker/build-push-action@v2
62+
with:
63+
context: .
64+
platforms: linux/amd64,linux/arm64
65+
file: ${{ matrix.props.Dockerfile }}
66+
tags: ${{ steps.meta.outputs.tags }}
67+
push: ${{ github.event_name != 'pull_request' }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@
99
# SASS
1010
.sass-cache
1111
*.css.map
12+
13+
# Certificates
14+
certs/

.travis.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ env:
88
services:
99
- docker
1010

11+
arch:
12+
- amd64
13+
- arm64
14+
1115
script:
1216
- docker build -t nginxtest -f ${DOCKERFILE} .
1317
- mkdir certs

Dockerfile

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM behance/docker-base:3.0-ubuntu-20.04
1+
FROM behance/docker-base:4.0-ubuntu-20.04
22

33
# Use in multi-phase builds, when an init process requests for the container to gracefully exit, so that it may be committed
44
# Used with alternative CMD (worker.sh), leverages supervisor to maintain long-running processes
@@ -43,15 +43,11 @@ COPY --chown=www-data ./container/root /
4343
# Set nginx to listen on defined port
4444
# NOTE: order of operations is important, new config had to already installed from repo (above)
4545
# - Make temp directory for .nginx runtime files
46-
# - Remove older WOFF mime-type
47-
# - Add again with newer mime-type
48-
# - Also add mime-type for WOFF2
46+
# - Fix woff mime type support
4947
# Set permissions to allow image to be run under a non root user
5048
RUN sed -i "s/listen [0-9]*;/listen ${CONTAINER_PORT};/" $CONF_NGINX_SITE && \
5149
mkdir /tmp/.nginx && \
52-
sed -i "/application\/font-woff/d" /etc/nginx/mime.types && \
53-
sed -i "s/}/\n font\/woff woff;&/" /etc/nginx/mime.types && \
54-
sed -i "s/}/\n font\/woff2 woff2;\n&/g" /etc/nginx/mime.types && \
50+
/bin/bash -e /scripts/fix_woff_support.sh && \
5551
/bin/bash -e /scripts/set_permissions.sh
5652

5753
RUN goss -g /tests/ubuntu/nginx.goss.yaml validate && \

Dockerfile-alpine

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM behance/docker-base:3.0-alpine
1+
FROM behance/docker-base:4.0-alpine
22

33
# Use in multi-phase builds, when an init process requests for the container to gracefully exit, so that it may be committed
44
# Used with alternative CMD (worker.sh), leverages supervisor to maintain long-running processes

Dockerfile-centos

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM behance/docker-base:3.0-centos-7
1+
FROM behance/docker-base:4.0-centos-7
22

33
# Use in multi-phase builds, when an init process requests for the container to gracefully exit, so that it may be committed
44
# Used with alternative CMD (worker.sh), leverages supervisor to maintain long-running processes
@@ -12,11 +12,18 @@ ENV CONTAINER_ROLE=web \
1212
# Using a non-privileged port to prevent having to use setcap internally
1313
EXPOSE ${CONTAINER_PORT}
1414

15-
# - Update security packages, only
15+
# - Update security packages
16+
# - Install new stable version of nginx
1617
RUN /bin/bash -e /security_updates.sh && \
17-
yum -y -q install epel-release && \
18+
mkdir -p /etc/yum.repos.d && \
19+
echo $'[nginx-stable] \n\
20+
name=nginx stable repo \n\
21+
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ \n\
22+
gpgcheck=1 \n\
23+
enabled=1 \n\
24+
name=nginx stable repo \n\
25+
gpgkey=https://nginx.org/keys/nginx_signing.key' > /etc/yum.repos.d/nginx.repo && \
1826
yum -y -q install nginx ca-certificates && \
19-
yum -y -q remove epel-release && \
2027
/bin/bash -e /clean.sh
2128

2229
# Overlay the root filesystem from this repo
@@ -25,12 +32,15 @@ COPY --chown=nginx ./container/root /
2532
# - Set nginx to listen on defined port
2633
# - NOTE: order of operations is important, new config had to already installed from repo (above)
2734
# - Make temp directory for .nginx runtime files
35+
# - Fix woff mime type support
2836
# - Update nginx.conf user
2937
# - Set permissions to allow image to be run under a non root user
3038
RUN sed -i "s/listen [0-9]*;/listen ${CONTAINER_PORT};/" $CONF_NGINX_SITE && \
3139
mkdir /tmp/.nginx && \
40+
/bin/bash -e /scripts/fix_woff_support.sh && \
3241
sed -i "s/^user .*$/user ${NOT_ROOT_USER};/" ${CONF_NGINX_SERVER} && \
3342
/bin/bash -e /scripts/set_permissions.sh
3443

44+
RUN yum update -y -q nginx
3545
RUN goss -g /tests/centos/nginx.goss.yaml validate && \
3646
/aufs_hack.sh

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,32 @@ container's use is in configuration and process. The `./container/root` repo dir
105105
to the folders in there will be present in the final image.
106106

107107
Nginx is currently set up as an S6 service in `/etc/services-available/nginx`, during default environment conditions, it will symlink itself to be supervised under `/etc/services.d/nginx`. When running under worker entrypoint (`worker.sh`), it will not be S6's `service.d` folder to be supervised.
108+
109+
110+
### Release Management
111+
112+
Github actions provide the machinery for testing (ci.yaml) and producing tags distributed through Docker Hub (publish.yaml). Testing will confirm that `nginx` is able to serve content in various configurations, but also that it can terminate TLS with self-signed certificates. Once a tested and approved PR is merged, simply cutting a new semantically-versioned tag will generate the following matrix of tagged builds:
113+
- `[major].[minor].[patch](?-variant)`
114+
- `[major].[minor](?-variant)`
115+
- `[major](?-variant)`
116+
Platform support is available for architectures:
117+
- `linux/arm64`
118+
- `linux/amd64`
119+
120+
To add new variant based on a new Dockerfile, add an entry to `matrix.props` within `./github/workflows` YAML files.
121+
122+
### Github Actions: Simulation
123+
124+
docker-nginx uses Github Actions for CI/CD. Simulated workflows can be achieved locally with `act`. All commands must be executes from repository root.
125+
126+
Pre-reqs: tested on Mac
127+
1. [Docker Desktop](https://www.docker.com/products/docker-desktop)
128+
1. [act](https://github.com/nektos/act)
129+
130+
Pull request simulation: executes successfully, but only on ARM devices (ex. Apple M1). ARM emulation through QEMU on X64 machines does not implement the full kernel functionality required by nginx at this time.
131+
- `act pull_request`
132+
133+
Publish simulation: executes, but fails (intentionally) without credentials
134+
- `act`
135+
136+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash -e
2+
3+
# Removes legacy woff type
4+
sed -i "/application\/font-woff/d" /etc/nginx/mime.types
5+
6+
# Detects if woff support is already present
7+
if grep -Fxq "font/woff" /etc/nginx/mime.types
8+
then
9+
echo "Woff type detected, no changes necessary"
10+
else
11+
echo "Woff type not detected, adding..."
12+
sed -i "s/}/\n font\/woff woff;&/" /etc/nginx/mime.types
13+
sed -i "s/}/\n font\/woff2 woff2;\n&/g" /etc/nginx/mime.types
14+
fi

container/root/tests/common/nginx.goss.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ file:
5353
/etc/nginx/mime.types:
5454
exists: true
5555
contains:
56+
- '/#{0}text\/html/' # assert that file has basic content
5657
- '/#{0}font\/woff\s*woff;/'
5758
- '/#{0}font\/woff2\s*woff2;/'
5859
- '!/application\/font-woff/'

0 commit comments

Comments
 (0)