Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Docker build to support multiple OS architectures #89

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/workflows/docker-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Docker Image CI
on:
push:
tags:
- 'v*'

jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Docker Setup Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Azure Container Registry
uses: Azure/docker-login@v1
with:
username: ${{ secrets.ACR_USERNAME }}
password: ${{ secrets.ACR_PASSWORD }}
login-server: ${{ secrets.ACR_SERVER }}
- name: Build and push Docker image
run: |
docker buildx create --name mybuilder --driver docker-container --platform linux/amd64,linux/arm64 --bootstrap --use
docker buildx build --platform linux/amd64,linux/arm64 --tag ${{ secrets.ACR_SERVER }}/azure-vote-front:$(echo "${{ github.ref }}" | grep -oP 'refs/tags/\K(.+)') --push ./azure-vote
8 changes: 4 additions & 4 deletions azure-vote-all-in-one-redis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ spec:
app: azure-vote-back
spec:
nodeSelector:
"beta.kubernetes.io/os": linux
"kubernetes.io/os": linux
containers:
- name: azure-vote-back
image: mcr.microsoft.com/oss/bitnami/redis:6.0.8
image: redis:latest
env:
- name: ALLOW_EMPTY_PASSWORD
value: "yes"
Expand Down Expand Up @@ -54,10 +54,10 @@ spec:
app: azure-vote-front
spec:
nodeSelector:
"beta.kubernetes.io/os": linux
"kubernetes.io/os": linux
containers:
- name: azure-vote-front
image: mcr.microsoft.com/azuredocs/azure-vote-front:v1
image: cloudnativeadvocates.azurecr.io/azure-vote-front:v1.0.0
ports:
- containerPort: 80
resources:
Expand Down
102 changes: 99 additions & 3 deletions azure-vote/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,99 @@
FROM tiangolo/uwsgi-nginx-flask:python3.6
RUN pip install redis
ADD /azure-vote /app
# sources:
# https://github.com/tiangolo/uwsgi-nginx-docker/blob/master/docker-images/python3.6.dockerfile
# https://github.com/tiangolo/uwsgi-nginx-flask-docker/blob/master/docker-images/python3.6.dockerfile

FROM python:3.9-buster

#LABEL maintainer="Sebastian Ramirez <[email protected]>"

COPY install-nginx-debian.sh /

RUN bash /install-nginx-debian.sh

# Install requirements
COPY requirements.txt /tmp/requirements.txt
RUN pip install --no-cache-dir -r /tmp/requirements.txt

EXPOSE 80

# Expose 443, in case of LTS / HTTPS
EXPOSE 443

# Remove default configuration from Nginx
RUN rm /etc/nginx/conf.d/default.conf
# Copy the base uWSGI ini file to enable default dynamic uwsgi process number
COPY uwsgi.ini /etc/uwsgi/

# Install Supervisord
RUN apt-get update && apt-get install -y supervisor \
&& rm -rf /var/lib/apt/lists/*
# Custom Supervisord config
COPY supervisord-debian.conf /etc/supervisor/conf.d/supervisord.conf

# Copy stop-supervisor.sh to kill the supervisor and substasks on app failure
COPY stop-supervisor.sh /etc/supervisor/stop-supervisor.sh
RUN chmod +x /etc/supervisor/stop-supervisor.sh

# Which uWSGI .ini file should be used, to make it customizable
ENV UWSGI_INI /app/uwsgi.ini

# By default, run 2 processes
ENV UWSGI_CHEAPER 2

# By default, when on demand, run up to 16 processes
ENV UWSGI_PROCESSES 16

# By default, allow unlimited file sizes, modify it to limit the file sizes
# To have a maximum of 1 MB (Nginx's default) change the line to:
# ENV NGINX_MAX_UPLOAD 1m
ENV NGINX_MAX_UPLOAD 0

# By default, Nginx will run a single worker process, setting it to auto
# will create a worker for each CPU core
ENV NGINX_WORKER_PROCESSES 1

# By default, Nginx listens on port 80.
# To modify this, change LISTEN_PORT environment variable.
# (in a Dockerfile or with an option for `docker run`)
ENV LISTEN_PORT 80

# URL under which static (not modified by Python) files will be requested
# They will be served by Nginx directly, without being handled by uWSGI
ENV STATIC_URL /static

# Absolute path in where the static files wil be
ENV STATIC_PATH /app/static

# If STATIC_INDEX is 1, serve / with /static/index.html directly (or the static URL configured)
# ENV STATIC_INDEX 1
ENV STATIC_INDEX 0

# Make /app/* available to be imported by Python globally to better support several use cases like Alembic migrations.
ENV PYTHONPATH=/app

# Copy start.sh script that will check for a /app/prestart.sh script and run it before starting the app
COPY start.sh /start.sh
RUN chmod +x /start.sh

# Copy the entrypoint that will generate Nginx additional configs
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

# Add demo app
COPY ./azure-vote /app
WORKDIR /app
RUN ls

# Copy the base uwsgi-nginx-entrypoint to reuse it
COPY uwsgi-nginx-entrypoint.sh /uwsgi-nginx-entrypoint.sh
RUN chmod +x /uwsgi-nginx-entrypoint.sh

# Copy the entrypoint that will generate Nginx additional configs
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

# Run the start script, it will check for an /app/prestart.sh script (e.g. for migrations)
# And then will start Supervisor, which in turn will start Nginx and uWSGI
CMD ["/start.sh"]
11 changes: 11 additions & 0 deletions azure-vote/azure-vote/prestart.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#! /usr/bin/env sh

echo "Running inside /app/prestart.sh, you could add migrations to this file, e.g.:"

echo "
#! /usr/bin/env sh
# Let the DB start
sleep 10;
# Run migrations
alembic upgrade head
"
3 changes: 3 additions & 0 deletions azure-vote/azure-vote/uwsgi.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[uwsgi]
module = main
callable = app
46 changes: 46 additions & 0 deletions azure-vote/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#! /usr/bin/env sh
set -e

/uwsgi-nginx-entrypoint.sh

# Get the URL for static files from the environment variable
USE_STATIC_URL=${STATIC_URL:-'/static'}
# Get the absolute path of the static files from the environment variable
USE_STATIC_PATH=${STATIC_PATH:-'/app/static'}
# Get the listen port for Nginx, default to 80
USE_LISTEN_PORT=${LISTEN_PORT:-80}

if [ -f /app/nginx.conf ]; then
cp /app/nginx.conf /etc/nginx/nginx.conf
else
content_server='server {\n'
content_server=$content_server" listen ${USE_LISTEN_PORT};\n"
content_server=$content_server' location / {\n'
content_server=$content_server' try_files $uri @app;\n'
content_server=$content_server' }\n'
content_server=$content_server' location @app {\n'
content_server=$content_server' include uwsgi_params;\n'
content_server=$content_server' uwsgi_pass unix:///tmp/uwsgi.sock;\n'
content_server=$content_server' }\n'
content_server=$content_server" location $USE_STATIC_URL {\n"
content_server=$content_server" alias $USE_STATIC_PATH;\n"
content_server=$content_server' }\n'
# If STATIC_INDEX is 1, serve / with /static/index.html directly (or the static URL configured)
if [ "$STATIC_INDEX" = 1 ] ; then
content_server=$content_server' location = / {\n'
content_server=$content_server" index $USE_STATIC_URL/index.html;\n"
content_server=$content_server' }\n'
fi
content_server=$content_server'}\n'
# Save generated server /etc/nginx/conf.d/nginx.conf
printf "$content_server" > /etc/nginx/conf.d/nginx.conf
fi

# For Alpine:
# Explicitly add installed Python packages and uWSGI Python packages to PYTHONPATH
# Otherwise uWSGI can't import Flask
if [ -n "$ALPINEPYTHON" ] ; then
export PYTHONPATH=$PYTHONPATH:/usr/local/lib/$ALPINEPYTHON/site-packages:/usr/lib/$ALPINEPYTHON/site-packages
fi

exec "$@"
80 changes: 80 additions & 0 deletions azure-vote/install-nginx-debian.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#! /usr/bin/env bash

# From official Nginx Docker image, as a script to re-use it, removing internal comments
# Ref: https://github.com/nginxinc/docker-nginx/blob/f958fbacada447737319e979db45a1da49123142/mainline/debian/Dockerfile

# Standard set up Nginx
export NGINX_VERSION=1.21.6
export NJS_VERSION=0.7.3
export PKG_RELEASE=1~buster

set -x \
&& apt-get update \
&& apt-get install --no-install-recommends --no-install-suggests -y gnupg1 ca-certificates \
&& \
NGINX_GPGKEY=573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62; \
found=''; \
for server in \
ha.pool.sks-keyservers.net \
hkp://keyserver.ubuntu.com:80 \
hkp://p80.pool.sks-keyservers.net:80 \
pgp.mit.edu \
; do \
echo "Fetching GPG key $NGINX_GPGKEY from $server"; \
apt-key adv --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY" && found=yes && break; \
done; \
test -z "$found" && echo >&2 "error: failed to fetch GPG key $NGINX_GPGKEY" && exit 1; \
apt-get remove --purge --auto-remove -y gnupg1 && rm -rf /var/lib/apt/lists/* \
&& dpkgArch="$(dpkg --print-architecture)" \
&& nginxPackages=" \
nginx=${NGINX_VERSION}-${PKG_RELEASE} \
nginx-module-xslt=${NGINX_VERSION}-${PKG_RELEASE} \
nginx-module-geoip=${NGINX_VERSION}-${PKG_RELEASE} \
nginx-module-image-filter=${NGINX_VERSION}-${PKG_RELEASE} \
nginx-module-njs=${NGINX_VERSION}+${NJS_VERSION}-${PKG_RELEASE} \
" \
&& case "$dpkgArch" in \
amd64|i386|arm64) \
echo "deb https://nginx.org/packages/mainline/debian/ buster nginx" >> /etc/apt/sources.list.d/nginx.list \
&& apt-get update \
;; \
*) \
echo "deb-src https://nginx.org/packages/mainline/debian/ buster nginx" >> /etc/apt/sources.list.d/nginx.list \
\
&& tempDir="$(mktemp -d)" \
&& chmod 777 "$tempDir" \
\
&& savedAptMark="$(apt-mark showmanual)" \
\
&& apt-get update \
&& apt-get build-dep -y $nginxPackages \
&& ( \
cd "$tempDir" \
&& DEB_BUILD_OPTIONS="nocheck parallel=$(nproc)" \
apt-get source --compile $nginxPackages \
) \
\
&& apt-mark showmanual | xargs apt-mark auto > /dev/null \
&& { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \
\
&& ls -lAFh "$tempDir" \
&& ( cd "$tempDir" && dpkg-scanpackages . > Packages ) \
&& grep '^Package: ' "$tempDir/Packages" \
&& echo "deb [ trusted=yes ] file://$tempDir ./" > /etc/apt/sources.list.d/temp.list \
&& apt-get -o Acquire::GzipIndexes=false update \
;; \
esac \
\
&& apt-get install --no-install-recommends --no-install-suggests -y \
$nginxPackages \
gettext-base \
curl \
&& apt-get remove --purge --auto-remove -y && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx.list \
\
&& if [ -n "$tempDir" ]; then \
apt-get purge -y --auto-remove \
&& rm -rf "$tempDir" /etc/apt/sources.list.d/temp.list; \
fi \
&& ln -sf /dev/stdout /var/log/nginx/access.log \
&& ln -sf /dev/stderr /var/log/nginx/error.log \
# Standard set up Nginx finished
3 changes: 3 additions & 0 deletions azure-vote/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
uwsgi==2.0.20
flask==2.0.1
redis==4.3.4
15 changes: 15 additions & 0 deletions azure-vote/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#! /usr/bin/env sh
set -e

# If there's a prestart.sh script in the /app directory, run it before starting
PRE_START_PATH=/app/prestart.sh
echo "Checking for script in $PRE_START_PATH"
if [ -f $PRE_START_PATH ] ; then
echo "Running script $PRE_START_PATH"
. $PRE_START_PATH
else
echo "There is no script $PRE_START_PATH"
fi

# Start Supervisor, with Nginx and uWSGI
exec /usr/bin/supervisord
16 changes: 16 additions & 0 deletions azure-vote/stop-supervisor.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env sh

# Ref:
# * https://github.com/tiangolo/uwsgi-nginx-docker/issues/61#issuecomment-508034634
# * https://gist.github.com/ReallyLiri/f833510d350b242ff89b9b76fdf21ea5
# * https://serverfault.com/a/922943
# * https://gist.github.com/tomazzaman/63265dfab3a9a61781993212fa1057cb
# * https://gist.github.com/tomazzaman/63265dfab3a9a61781993212fa1057cb#gistcomment-2812931
# * https://github.com/Supervisor/supervisor/issues/733
# *
printf "READY\n";

while read line; do
echo "Processing Event: $line" >&2;
kill $PPID
done < /dev/stdin
26 changes: 26 additions & 0 deletions azure-vote/supervisord-debian.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[supervisord]
nodaemon=true

[program:uwsgi]
command=/usr/local/bin/uwsgi --ini /etc/uwsgi/uwsgi.ini
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
startsecs = 0
autorestart=false

[program:nginx]
command=/usr/sbin/nginx
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
# Graceful stop, see http://nginx.org/en/docs/control.html
stopsignal=QUIT
startsecs = 0
autorestart=false

[eventlistener:quit_on_failure]
events=PROCESS_STATE_STOPPED,PROCESS_STATE_EXITED,PROCESS_STATE_FATAL
command=/etc/supervisor/stop-supervisor.sh
Loading