Skip to content

Commit

Permalink
Dockerfile: updated bases to 4.0 (#78)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
bryanlatten and Bryan Latten authored Dec 15, 2021
1 parent 41248ef commit 7f68f49
Show file tree
Hide file tree
Showing 10 changed files with 237 additions and 12 deletions.
101 changes: 101 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
name: ci

on:
pull_request:
branches: [ master ]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
props:
- Dockerfile: Dockerfile
- Dockerfile: Dockerfile-alpine
- Dockerfile: Dockerfile-centos
platform:
- linux/amd64
- linux/arm64
env:
TEST_MATCH: Welcome to nginx!
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Detect host configuration
run: |
# NOTE: Docker host configuration determines the networking target for integration testing
v=$(mount | grep "/run/docker.sock")
TARGET_HOST=
if [ -n "$v" ]; then
echo "Injected docker socket detected"
TARGET_HOST="host.docker.internal"
elif [ -S /var/run/docker.sock ]; then
TARGET_HOST="localhost"
else
echo "No Docker socket detected, fail"
exit 1
fi
echo "TARGET_HOST=${TARGET_HOST}" >> $GITHUB_ENV
-
# Build and execute in multiple configurations: vanilla, with env overrides, with TLS enabled
name: Build and test
run: |
# NOTE: docker qemu and buildx setup actions create a black hole for build cache layers, avoid unless pushing externally
# Setup multi-arch platforms, noop if already installed for builder
docker run --privileged --rm tonistiigi/binfmt --install arm64,amd64
TARGET_PLATFORM=${{ matrix.platform }}
TARGET_DOCKERFILE=${{ matrix.props.Dockerfile }}
# Since containers may or may not be against the same docker engine, create a matrix-unique tag name for outputs
TAG_NAME="docker-nginx-${TARGET_DOCKERFILE}-${TARGET_PLATFORM}"
# Formats as lowercase
TAG_NAME=$(echo $TAG_NAME | tr '[:upper:]' '[:lower:]')
# Removes slashes
TAG_NAME=$(echo $TAG_NAME | sed 's/\///')
echo $TAG_NAME
docker buildx build --platform $TARGET_PLATFORM --iidfile $TAG_NAME -t $TAG_NAME -f $TARGET_DOCKERFILE .
# NOTE: multi-arch builds may not be accessible by docker tag, instead target by ID
BUILD_SHA=$(cat ./$TAG_NAME)
# Remove sha256: from tag identifier
BUILD_SHA=$(echo $BUILD_SHA | sed 's/sha256\://')
# Generate self-signed certificates
mkdir -p certs
openssl genrsa -out ./certs/ca.key 2048
openssl req -new -key ./certs/ca.key -out ./certs/ca.csr -subj '/CN=localhost'
openssl x509 -req -days 365 -in ./certs/ca.csr -signkey ./certs/ca.key -out ./certs/ca.crt
# Run various configurations of containers
CONTAINER_VANILLA=$(docker run --platform $TARGET_PLATFORM --rm -p 8080 -d $BUILD_SHA)
CONTAINER_ENV_FILE=$(docker run --platform $TARGET_PLATFORM --rm -p 8080 -d --env-file ./.test.env $BUILD_SHA)
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)
# Retrieve dynamically-allocated host port
VANILLA_PORT=$(docker inspect --format '{{ (index (index .NetworkSettings.Ports "8080/tcp") 0).HostPort }}' $CONTAINER_VANILLA)
ENV_FILE_PORT=$(docker inspect --format '{{ (index (index .NetworkSettings.Ports "8080/tcp") 0).HostPort }}' $CONTAINER_ENV_FILE)
HTTPS_PORT=$(docker inspect --format '{{ (index (index .NetworkSettings.Ports "8080/tcp") 0).HostPort }}' $CONTAINER_HTTPS)
# Wait for containers to boot (in background)
sleep 5
TARGET_HOST=${{ env.TARGET_HOST }}
echo "HOSTING ${TARGET_HOST}"
# Check for nginx test page response
curl ${TARGET_HOST}:${VANILLA_PORT} | grep "${{ env.TEST_MATCH }}"
curl ${TARGET_HOST}:${ENV_FILE_PORT} | grep "${{ env.TEST_MATCH }}"
curl -k https://${TARGET_HOST}:${HTTPS_PORT} | grep "${{ env.TEST_MATCH }}"
# Cleanup
docker kill $CONTAINER_VANILLA
docker kill $CONTAINER_ENV_FILE
docker kill $CONTAINER_HTTPS
docker rmi $BUILD_SHA
67 changes: 67 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: publish

on:
push:
tags:
- '*'

jobs:
publish:
runs-on: ubuntu-latest
env:
IMAGE_BASE: behance/docker-nginx
strategy:
matrix:
props:
# This is the default variant-less distribution (ex. 3.2.1)
- Dockerfile: Dockerfile
# Variant distributions below all have semantic versions + suffix (ex. 3.2.1-alpine)
- Dockerfile: Dockerfile-alpine
suffix: alpine
- Dockerfile: Dockerfile-centos
suffix: centos
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Add tag suffix
if: matrix.props.suffix
run: |
echo TAG_SUFFIX="-${{ matrix.props.suffix }}" >> $GITHUB_ENV
-
name: Docker meta
id: meta
if: github.event_name != 'pull_request'
uses: docker/metadata-action@v3
with:
images: ${{ env.IMAGE_BASE }}
tags: |
type=semver,pattern={{major}}.{{minor}}.{{patch}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
flavor: |
latest=auto
suffix=${{ env.TAG_SUFFIX }}
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
-
name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build + push
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/amd64,linux/arm64
file: ${{ matrix.props.Dockerfile }}
tags: ${{ steps.meta.outputs.tags }}
push: ${{ github.event_name != 'pull_request' }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@
# SASS
.sass-cache
*.css.map

# Certificates
certs/
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ env:
services:
- docker

arch:
- amd64
- arm64

script:
- docker build -t nginxtest -f ${DOCKERFILE} .
- mkdir certs
Expand Down
10 changes: 3 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM behance/docker-base:3.0-ubuntu-20.04
FROM behance/docker-base:4.0-ubuntu-20.04

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

RUN goss -g /tests/ubuntu/nginx.goss.yaml validate && \
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile-alpine
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM behance/docker-base:3.0-alpine
FROM behance/docker-base:4.0-alpine

# Use in multi-phase builds, when an init process requests for the container to gracefully exit, so that it may be committed
# Used with alternative CMD (worker.sh), leverages supervisor to maintain long-running processes
Expand Down
18 changes: 14 additions & 4 deletions Dockerfile-centos
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM behance/docker-base:3.0-centos-7
FROM behance/docker-base:4.0-centos-7

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

# - Update security packages, only
# - Update security packages
# - Install new stable version of nginx
RUN /bin/bash -e /security_updates.sh && \
yum -y -q install epel-release && \
mkdir -p /etc/yum.repos.d && \
echo $'[nginx-stable] \n\
name=nginx stable repo \n\
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ \n\
gpgcheck=1 \n\
enabled=1 \n\
name=nginx stable repo \n\
gpgkey=https://nginx.org/keys/nginx_signing.key' > /etc/yum.repos.d/nginx.repo && \
yum -y -q install nginx ca-certificates && \
yum -y -q remove epel-release && \
/bin/bash -e /clean.sh

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

RUN yum update -y -q nginx
RUN goss -g /tests/centos/nginx.goss.yaml validate && \
/aufs_hack.sh
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,32 @@ container's use is in configuration and process. The `./container/root` repo dir
to the folders in there will be present in the final image.

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.


### Release Management

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:
- `[major].[minor].[patch](?-variant)`
- `[major].[minor](?-variant)`
- `[major](?-variant)`
Platform support is available for architectures:
- `linux/arm64`
- `linux/amd64`

To add new variant based on a new Dockerfile, add an entry to `matrix.props` within `./github/workflows` YAML files.

### Github Actions: Simulation

docker-nginx uses Github Actions for CI/CD. Simulated workflows can be achieved locally with `act`. All commands must be executes from repository root.

Pre-reqs: tested on Mac
1. [Docker Desktop](https://www.docker.com/products/docker-desktop)
1. [act](https://github.com/nektos/act)

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.
- `act pull_request`

Publish simulation: executes, but fails (intentionally) without credentials
- `act`


14 changes: 14 additions & 0 deletions container/root/scripts/fix_woff_support.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash -e

# Removes legacy woff type
sed -i "/application\/font-woff/d" /etc/nginx/mime.types

# Detects if woff support is already present
if grep -Fxq "font/woff" /etc/nginx/mime.types
then
echo "Woff type detected, no changes necessary"
else
echo "Woff type not detected, adding..."
sed -i "s/}/\n font\/woff woff;&/" /etc/nginx/mime.types
sed -i "s/}/\n font\/woff2 woff2;\n&/g" /etc/nginx/mime.types
fi
1 change: 1 addition & 0 deletions container/root/tests/common/nginx.goss.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ file:
/etc/nginx/mime.types:
exists: true
contains:
- '/#{0}text\/html/' # assert that file has basic content
- '/#{0}font\/woff\s*woff;/'
- '/#{0}font\/woff2\s*woff2;/'
- '!/application\/font-woff/'

0 comments on commit 7f68f49

Please sign in to comment.