Skip to content

Commit

Permalink
Merge pull request #25 from bryanlatten/feature-s6
Browse files Browse the repository at this point in the history
Dockerfile: removed supervisor, added S6
  • Loading branch information
Bryan Latten committed Mar 18, 2016
2 parents 9c7e204 + 3a76c4b commit efeae27
Show file tree
Hide file tree
Showing 16 changed files with 153 additions and 72 deletions.
51 changes: 35 additions & 16 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,49 @@ ENV SIGNAL_BUILD_STOP=99 \
CONTAINER_ROLE=web \
CONF_NGINX_SITE="/etc/nginx/sites-available/default" \
CONF_NGINX_SERVER="/etc/nginx/nginx.conf" \
NOT_ROOT_USER=docker
NOT_ROOT_USER=www-data \
S6_BEHAVIOUR_IF_STAGE2_FAILS=2 \
S6_KILL_FINISH_MAXTIME=5000 \
S6_KILL_GRACETIME=3000

# Create an unprivileged user
RUN useradd -r -s /bin/false $NOT_ROOT_USER

# Ensure base system is up to date
RUN apt-get update && \
apt-get install -yq \
openssl \
ca-certificates \
apt-get upgrade -yqq && \
# Install pre-reqs \
apt-get install -yqq \
software-properties-common \
supervisor \
nano \
&& \
rm -rf /var/lib/apt/lists/*

# Install latest nginx (development PPA is actually mainline development)
RUN add-apt-repository ppa:nginx/development -y && \
apt-get update -yq && \
apt-get install -yq nginx \
# Install latest nginx (development PPA is actually mainline development) \
add-apt-repository ppa:nginx/development -y && \
apt-get update -yqq && \
apt-get install -yqq nginx \
&& \
rm -rf /var/lib/apt/lists/*
# Perform cleanup, ensure unnecessary packages are removed \
apt-get remove --purge -yq \
manpages \
manpages-dev \
man-db \
patch \
make \
unattended-upgrades \
python* \
&& \
apt-get autoclean -y && \
apt-get autoremove -y && \
rm -rf /var/lib/{cache,log}/ && \
rm -rf /var/lib/apt/lists/ && \
rm -rf /tmp/* /var/tmp/*

# # Overlay the root filesystem from this repo
# Overlay the root filesystem from this repo
COPY ./container/root /

# Add S6 overlay build, to avoid having to build from source
RUN tar xzf /tmp/s6-overlay-amd64.tar.gz -C / && \
rm /tmp/s6-overlay-amd64.tar.gz

EXPOSE 80

# NOTE: intentionally NOT using s6 init as the entrypoint
# This would prevent container debugging if any of those service crash
CMD ["/bin/bash", "/run.sh"]
48 changes: 39 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,60 @@
# docker-nginx
Provides base OS, patches and stable nginx for quick and easy spinup
Provides base OS, patches and stable nginx for quick and easy spinup.
Integrates S6 process supervisor for zombie reaping (as PID 1) and boot coordination.
@see https://github.com/just-containers/s6-overlay

### Expectations

Applications using this as a container parent must copy their html/app into the `/var/www/html` folder



### Environment Variables

Variable | Example | Description
--- | --- | ---
`SERVER_MAX_BODY_SIZE` | `SERVER_MAX_BODY_SIZE=4M` | Allows the downstream application to specify a non-default `client_max_body_size` configuration for the `server`-level directive in `/etc/nginx/sites-available/default`
`SERVER_INDEX` | `SERVER_INDEX index.html index.html index.php` | Changes the default pages to hit for folder and web roots
`SERVER_APP_NAME` | `SERVER_APP_NAME='view'` | Sets a kv pair to be consumed by logging service for easy parsing and searching
`SERVER_APP_NAME` | `SERVER_APP_NAME='view'` | Gets appended to the default logging format
`SERVER_GZIP_OPTIONS` | `SERVER_GZIP_OPTIONS=1` | Allows default set of static content to be served gzipped
`SERVER_SENDFILE` | `SERVER_SENDFILE=off` | Allows runtime to specify value of nginx's `sendfile` (default, on)
`SERVER_KEEPALIVE` | `SERVER_KEEPALIVE=30` | Define HTTP 1.1's keepalive timeout
`SERVER_WORKER_CONNECTIONS` | `SERVER_WORKER_CONNECTIONS=2048` | Sets up the number of connections for worker processes
`SERVER_LOG_MINIMAL` | `SERVER_LOG_MINIMAL=1` | Minimize the logging format, appropriate for development environments
`S6_KILL_FINISH_MAXTIME` | `S6_KILL_FINISH_MAXTIME=1000` | Wait time (in ms) for zombie reaping before sending a kill signal
`S6_KILL_GRACETIME` | `S6_KILL_GRACETIME=500` | Wait time (in ms) for S6 finish scripts before sending kill signal


### Startup/Runtime Modification

To inject changes just before runtime, shell scripts (ending in .sh) may be placed into the
`/etc/cont-init.d` folder. For example, the above environment variables are used to drive nginx configuration at runtime.
As part of the process manager, these scripts are run in advance of the supervised processes. @see https://github.com/just-containers/s6-overlay#executing-initialization-andor-finalization-tasks

### Runtime Commands

To inject things into the runtime process, add shell scripts (ending in .sh) into the
`/run.d` folder. These will be executed during container start.
### Advanced Modification

- If script terminates with a non-zero exit code, container will stop, terminating with the script's exit code, unless...
- If script terminates with exit code of $SIGNAL_BUILD_STOP (99), this will signal the container to stop cleanly. This can be used for multi-stage builds that can be committed
More advanced changes can take effect using the run.d system. Similar to the `/etc/cont-init.d/` script system, any scripts (ending in .sh) in the `/run.d/` folder will be executed ahead of the S6 initialization.

- If run.d script terminates with a non-zero exit code, container will stop, terminating with the script's exit code, unless...
- If script terminates with exit code of $SIGNAL_BUILD_STOP (99), this will signal the container to stop cleanly. This can be used for multi-stage builds

### Long-running processes (workers)

### Long-running processes (workers + crons)

This container image can be shared between web and non-web processes. An example use case would be
a web service and codebase that also has a few crons and background workers. To reuse this container for
those types of workloads:

`docker run {image_id} /worker.sh 3 /bin/binary -parameters -that -binary -receives`

Runs 3 copies of `/bin/binary` that receives any arguments as parameters
Runs `3` copies of `/bin/binary` that receives the parameters `-parameters -that -binary -receives`


### Container Organization

Besides the instructions contained in the Dockerfile, the majority of this
container's use is in configuration and process. The `./container/root` repo directory is overlayed into a container during build. Adding additional files
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.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/with-contenv bash

if [[ $SERVER_APP_NAME ]]
then
Expand Down
1 change: 1 addition & 0 deletions container/root/etc/fix-attrs.d/01-stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/dev/stdout false www-data 0644 2700
4 changes: 4 additions & 0 deletions container/root/etc/fix-attrs.d/02-tmp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Shouldn't need to be two separate statements, something is requiring it
/tmp/.nginx true www-data 0644 2700
/tmp true www-data 0644 2700

18 changes: 10 additions & 8 deletions container/root/etc/nginx/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
# add to the run.d/nginx script
#############################################################

user www-data;
# Only set when running with superuser permissions, otherwise causes a warning
# user www-data;

worker_processes auto;

pid /tmp/nginx.pid;
pid /tmp/.nginx/nginx.pid;

events {
# @see http://serverfault.com/questions/209014/how-can-i-observe-what-nginx-is-doing-to-solve-1024-worker-connections-are-n
Expand All @@ -28,7 +30,7 @@ http {

log_format minimal '$request_method $request_uri $status';

error_log /dev/stdout info;
error_log /dev/stdout;
access_log /dev/stdout main;

sendfile on;
Expand All @@ -38,11 +40,11 @@ http {

#gzip on;

client_body_temp_path /tmp/client_body;
fastcgi_temp_path /tmp/fastcgi_temp;
proxy_temp_path /tmp/proxy_temp;
scgi_temp_path /tmp/scgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
client_body_temp_path /tmp/.nginx/client_body;
fastcgi_temp_path /tmp/.nginx/fastcgi_temp;
proxy_temp_path /tmp/.nginx/proxy_temp;
scgi_temp_path /tmp/.nginx/scgi_temp;
uwsgi_temp_path /tmp/.nginx/uwsgi_temp;

# Everything available is enabled in the container
include /etc/nginx/sites-available/*;
Expand Down
7 changes: 7 additions & 0 deletions container/root/etc/services-available/nginx/finish
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/execlineb -S1

# @see https://github.com/just-containers/s6-overlay/issues/101
if { s6-test ${1} -ne 0 }
if { s6-test ${1} -ne 256 }

s6-svscanctl -t /var/run/s6/services
4 changes: 4 additions & 0 deletions container/root/etc/services-available/nginx/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/execlineb -P
s6-setuidgid www-data

nginx -g "daemon off;"
Empty file.
37 changes: 21 additions & 16 deletions container/root/init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,30 @@ STATUS=0
# When .sh run scripts fail (exit non-zero), container run will fail
# NOTE: if a .sh script exits with 99, this is a stop signal, container must exit cleanly

for file in $RUN_SCRIPTS/*.sh; do
if ls ${RUN_SCRIPTS}/*.sh &>/dev/null
then
for file in $RUN_SCRIPTS/*.sh; do

echo "[init] executing ${file}"
echo "[init] executing ${file}"

# Note: -e will enforce that any subcommand that fails will fail the entire script run
/bin/bash -e $file
# Note: -e will enforce that any subcommand that fails will fail the entire script run
/bin/bash -e $file

STATUS=$? # Captures exit code from script that was run
STATUS=$? # Captures exit code from script that was run

if [[ $STATUS == $SIGNAL_BUILD_STOP ]]
then
echo "[init] exit signalled - ${file}"
exit $STATUS
fi
if [[ $STATUS == $SIGNAL_BUILD_STOP ]]
then
echo "[init] exit signalled - ${file}"
exit $STATUS
fi

if [[ $STATUS != 0 ]]
then
echo "[init] failed executing - ${file}"
exit $STATUS
fi
if [[ $STATUS != 0 ]]
then
echo "[init] failed executing - ${file}"
exit $STATUS
fi

done
done
else
echo "[init] no run.d scripts"
fi
13 changes: 13 additions & 0 deletions container/root/run.d/99-nginx.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash

# Ensure that worker entrypoint does not also run nginx processes
if [ $CONTAINER_ROLE == 'web' ]
then
echo '[run] enabling web server'

# Unfortunately, until Dockerhub supports this operation...it has to be done here
setcap cap_net_bind_service=+ep /usr/sbin/nginx

# Enable nginx as a supervised service
ln -s /etc/services-available/nginx /etc/services.d/nginx
fi
7 changes: 0 additions & 7 deletions container/root/run.d/README

This file was deleted.

6 changes: 3 additions & 3 deletions container/root/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ then
exit $STATUS
fi

# Primary command - starting webserver
echo "[nginx] start (foreground)"
exec /usr/sbin/nginx -g "daemon off;"
# Start process manager
echo "[run] starting process manager"
exec /init
Empty file.
Binary file added container/root/tmp/s6-overlay-amd64.tar.gz
Binary file not shown.
27 changes: 15 additions & 12 deletions container/root/worker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# Based on configuration, can run multiple instances of a single worker process

SUPERVISOR_CONF=/etc/supervisor/conf.d/worker.conf
SERVICES_D=/etc/services.d

# Signal to init processes to avoid any webserver startup
export CONTAINER_ROLE='worker'
Expand Down Expand Up @@ -42,17 +43,19 @@ fi

echo "[worker] command: '${WORKER_COMMAND}' quantity: ${WORKER_QUANTITY}"

echo "\
[program:worker]
command=${WORKER_COMMAND}
process_name=%(program_name)s%(process_num)s
numprocs=${WORKER_QUANTITY}
autorestart=true
redirect_stderr=true
stdout_logfile_maxbytes=0
stdout_logfile=/dev/stdout" > $SUPERVISOR_CONF
for i in `seq 1 $WORKER_QUANTITY`;
do
SERVICE_FOLDER="${SERVICES_D}/worker-${i}"
mkdir $SERVICE_FOLDER
echo "\
#!/usr/bin/execlineb -P
echo "[worker] entering supervisor"
with-contenv
s6-setuidgid ${NOT_ROOT_USER}
${WORKER_COMMAND}" > "${SERVICE_FOLDER}/run"
done

# Start process manager
echo "[run] starting process manager"
exec /init

# Primary command - starting supervisor after writing with worker program config file
exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf --nodaemon

0 comments on commit efeae27

Please sign in to comment.