Docker

This page describes how to use the Docker builds of TurnKey Linux appliances. Use of TurnKey Docker builds requires you have a host system with Docker installed. If you wish to install Docker on an existing TurnKey appliance, please consult the instructions for Debian (TurnKey v15.x = Debian 9/Stretch).

Please note that these are "full OS" style containers, rather than "application" style containers as many Docker users might normally expect. As such, these containers provide a full TurnKey (Debian based) OS and include all the software components of the other alternate TurnKey appliance download options (e.g. ISO, etc). They are provide an environment more like an LXC container user might expect, but optimised to run on Docker.

This page is an updated and improved version of the original Docker builds announcement.

Docker builds

These are TurnKey builds optimized to run as docker containers, supporting automatic download via the docker public index.

All TurnKey appliances are available on the Docker Hub (generously provided by Docker, Inc), which streamlines deployment. For example:

docker pull turnkeylinux/core
docker run -i -t -d turnkeylinux/core

Docker containers can be run in the foreground or the background, so we've tried our best to support all use cases with regards to initialization (aka. inithooks) - secret regeneration, setting of passwords, application configuration, etc.

Depending on your use case, we recommend two options:

Option 1: Initialization via ssh (interactive)

On first login, you will be prompted to initialize the appliance.

CID=$(docker run -i -t -d turnkeylinux/core)
CIP=$(docker inspect --format='{{.NetworkSettings.IPAddress}}' $CID)
docker logs $CID | grep "Random initial root password"
ssh root@$CIP

Option 2: Create new image with preseeded values (non-interactive)

The appliance will initialize itself with the provided configuration. Once initialized, the configuration will be deleted. For more information see inithooks.

To use WordPress as an example:

mkdir /root/wordpress

cat > /root/wordpress/inithooks.conf <<EOF
export ROOT_PASS=secretrootpass
export DB_PASS=secretmysqlpass
export APP_PASS=secretadminwppass
export APP_EMAIL=admin@example.com
export APP_DOMAIN=www.example.com
export HUB_APIKEY=SKIP
export SEC_UPDATES=FORCE
EOF

cat > /root/wordpress/Dockerfile <<EOF
FROM turnkeylinux/wordpress
ADD inithooks.conf /etc/inithooks.conf
EOF

docker build -t wordpress /root/wordpress
docker run -i -t -d wordpress

Notes

Docker tags and pulling/running different TurnKey versions

Prior to TurnKey v15.0, each individual TurnKey appliance Docker build release included the TurnKey version in the name. E.g. v14.2 TurnKey Core was on the Docker Hub as "turnkeylinux/core-14.2". So if you wish to use older TurnKey appliances (<15.0) then you will need to include the specific version number as part of the name. E.g. to pull and run TurnKey Core v14.2:

docker pull turnkeylinux/core-14.2
docker run -i -t -d turnkeylinux/core-14.2

However as of v15.0+, we are using Docker tags as a much better way of providing different versions of our appliances. Tags can be (optionally) specified when using the docker commandline tool by appending a colon (:) and the tag name. The "latest" tag always points to the latest update, and if a tag is not specified, then "latest" is assumed. So to pull and run the latest release of TurnKey core, you can use either of these examples:

docker pull turnkeylinux/core
docker run -i -t -d turnkeylinux/core

Or if you wish to be verbose:

docker pull turnkeylinux/core:latest
docker run -i -t -d turnkeylinux/core:latest

If you wish to download a specific release (>=15.0) then you can specify the desired version as a tag. So to use the Drupal 8 appliance as an example, if you wished to pull and run the v15.4 version, you could do that like this:

docker pull turnkeylinux/drupal8:15.4
docker run -i -t -d turnkeylinux/drupal8:15.4

Pre-configured run command

Docker is designed for "application or process" containers - for example, running mysql, and only mysql. Docker short-circuits /sbin/init so you can't really "boot" a container like in vanilla LXC.

To work around this, we've included /usr/sbin/start.sh (default run command) which will start all services and drop to a shell. When the shell is exited, the services will be stopped. For this reason, SSH is recommended for regular console usage.

STDIN and TTY options required

The -i and -t options are required to attach STDIN and allocate a TTY to the container. There have been moves by Docker to allow this to be pre-configured but we haven't yet looked deeper into that and are not up to date on hte current state of play.

Pre-configured to expose ports

All TurnKey Docker appliances are configured to expose their custom services. This means that the host can access the services, but they are not exposed to the network.

Exposing ports to the network needs to be done at runtime (docs), for example:

# bind port 80 on the host to the container's port 80
docker run -i -t -d -p 80:80 turnkeylinux/lamp

Or to use an alternate host port:

# bind port 8080 on the host to the container's port 80
docker run -i -t -d -p 0.0.0.0:8080:80 turnkeylinux/lamp

Skipping security updates on first boot

To speed up testing during development, support for overriding the default SEC_UPDATES value was added to start.sh. It was planned to remove this support or leave it undocumented, but we decided others might find it useful when testing (and only in testing!).

# THIS IS NOT RECOMMENDED, USE AT YOUR OWN RISK!
docker run -i -t -d -e SEC_UPDATES=SKIP turnkeylinux/openldap

Comments

Patrice Lazareff's picture

Hello, When calling a container from a docker-compose file (image: turnkeylinux/lamp-14.2) it starts well and stops immediately as I guess the shell called by start.sh is automatically exited by docker-compose. Any way around this, or am I missing something ? Kind regards, p@T
Jeremy Davis's picture

FWIW, it's probably best to post in the forums, rather than comment on docs. There is no easy way for me to see unanswered doc comments, so if I miss the initial notification in my inbox, the post will go answered (as happened to you here).

I'm not really sure why docker compose doesn't work as expected. Personally I'm not very familiar with Docker at all, let alone with docker compose. So I'm probably not much immediate help.

My guess is that you are correct. But how that might be addressed, I'm not really sure, sorry.

My hope is that it will be resolved when we finally move to our new appliance model (based on containers rather than a monolithic server). Then we will be building proper containers (rather than the hacky way we currently build them).

Having said that, that won't be happening anytime soon. So in the meantime, I've lodged it as a bug and will try to address it once we have our next release of appliance ISOs published (i.e. before we release the v15.0 Docker builds).

Bernhard Seebass's picture

docker stop <container> does not properly stop "turnkeylinux/core-14.2": the trap as defined in start.sh is not executed. Docker version 17.09.1-ce  running on Linux (OpenSuSE Tumbleweed) Here is a modified version of start.sh that worked for me (use sleep instead su and exit start.sh on recieving signal):
#!/bin/bash

# not recommended, useful for testing though...
if [ -n "$SEC_UPDATES" ]; then
    PRESEED=/usr/lib/inithooks/firstboot.d/29preseed
    sed -i "s|SEC_UPDATES=.*|SEC_UPDATES=$SEC_UPDATES|" $PRESEED
fi

run-parts -a start /etc/rc2.d
trap "run-parts -a stop /etc/rc2.d; exit 0" INT TERM EXIT

turnkey-sysinfo

if [ -x /root/.profile.d/turnkey-init-fence ]; then
cat<<EOF

WARNING: The container requires initialization (performed on first login).
This can be performed from the host as follows:

    CID=\$(docker ps -l -q)
    CIP=\$(docker inspect --format='{{.NetworkSettings.IPAddress}}' \$CID)
    docker logs \$CID | grep "Random initial root password"
    ssh root@\$CIP
EOF
fi

#cat<<EOF
#
#WARNING: Exiting this shell will stop the container.
#For regular console usage, SSH is recommended.
#EOF

#/bin/su

while true
do
    # wait for SIGINT, SIGTERM or SIGEXIT (see trap above)
    # signal is only recieved while not sleeping, therefore use a short sleep period
    sleep 0.5
done



 
Jeremy Davis's picture

And extra brownie points for the fix/workaround! :)

FWIW, I've open an issue on our tracker, so this doesn't get forgotten for our upcoming release.

Jeremy Davis's picture

One of our developers has had a look at this and couldn't reproduce your issue. See his comment on the issue.

If you can provide further info on how to recreate the issue that you experienced, we're more than happy to reopen it and investigate further.

Regardless, thanks for posting.