-
Unless you have a very good reason, always start with
unit9/base:latest
.-
It will be maintained for as long as
debian:jessie
will be receiving security updates. It will always be based on Debian Jessie; when a new Debian release happens, a new base image will be created, so that all the old images at least can still build. -
Debian's official Docker images are patched/rebuilt less frequently than
unit9/base
, and often include vulnerable packages. -
Our base image runs a
dist-upgrade
on each rebuild, thus security fixes appear approximately as soon as they're in Debian's repositories.
-
-
Automate as much as you can.
-
You will NOT feel like coming back here to rebuild and update all of your images by hand, every time glibc gets a CVE.
-
Use Docker Hub's automated builds feature, or other CI system. At least, ensure your own image is rebuilt every time:
- The
master
branch is updated, and/or unit9/base
image is updated
- The
-
-
Document everything.
- Link to upstream docs.
- Don't be shy to put inline comments.
- Explain how your integration with Docker differs from the usual / "orthodox" setup.
- Include examples for configuring and running your image with various tools / platforms (like k8s or docker-compose), or how to make it play nice with other dockerized apps.
-
Copy the
example
directory with all of its structure. -
Look at each and every file you copied: there are comments with
TODO
near every line that needs your action. Most importantly:- Inspect the
Makefile
, change theNAME
. - Build the
Dockerfile
to suit your application. Pay attention to how the layers are structured, to optimize the use of build caches. - Use the provided
rc.local
and*.run
files as examples on how to make your package work with therunit
init system. (Check the section "Working withrunit
"!)
- Inspect the
-
Run
make build
,make run
, etc. to make sure your image builds & behaves as intended. If ready, you can push a build to Docker Hub withmake push
, but better ensure the build is fully automated. -
Create a pull request against
unit9/docklabs
/master
!
runit
is an extremely lightweight init
scheme. It was made to run on "classic" Unix hosts, but its overall
architecture made it easy to adapt to running in containers.
- Create and/or override the file
/etc/rc.local
. - Make sure it's executable (commit it with the
+x
bit in git). - Make it exit with a >0 status if things go wrong (failed to validate config file, etc). This will make the container exit with a failed status code, which is easily detected by monitoring in production.
-
Many daemons are designed to fork; read up the manual page to find the flag or config file stanza to stop it from forking. For example:
nginx
needs a-g "daemon off;"
flag, or adaemon off;
directive in itsnginx.conf
file;anacron
needs a-d
flag;transmission-daemon
needs an-f
flag; etc.
-
Create an executable file that follows this general pattern:
#!/bin/sh set -eu exec mydaemon --no-fork
-
Save it as
mydaemon.run
. -
Add this layer near the bottom of your
Dockerfile
:ADD mydaemon.run /etc/service/mydaemon/run
Most important things to note, you will almost certainly NOT need to do any of these:
-
Do not set or override
ENTRYPOINT
orCMD
in yourDockerfile
; -
Do not fork; do not use pid files - this is already standard practice with Docker.
Other important things to note:
-
While you can run more than one service per container, remember to split things up logically, so the container is concerned with one "thing" (e.g. it's OK to run a web server to serve static files, and reverse proxy into a FastCGI program, that runs as another service).
-
Remember to
exec
at the end of the script, to avoid having a lingering shell process between init and your program.
- Log in to Docker Hub;
- Click "create" / "create automated build";
- Select Github; authorize to read public repos;
- Select
unit9/docklabs
as source repository; or use other source repository if appropriate; - Pick namespace and name; namespace should be
unit9
for stuff inunit9/docklabs
; name should be EXACTLY the same asNAME
in yourMakefile
(if usingcommon.mk
); - Add a one-liner description and hit "click here to customize";
- For each rule, change "Dockerfile location" to a sub-path in the repository that includes your stuff; you may also want to change wildcard branch builds to wildcard tag builds;
- Hit "create", go to "build settings";
- If your image's source is in
unit9/docklabs
and it descends from another image in this repository, you will want to un-check the box next to "builds will happen automatically on pushes", and instead, go to "repository links" and add dependencies on your base image (most usually onlyunit9/base
).
Check this example for a correctly configured automated build.