baseimage-amzn is a Docker Base Image that is configured for use within Docker containers. It is based on Amazon Linux Container Image, plus:
- Modifications for Docker-friendliness.
- Administration tools that are useful in the context of Docker.
- Mechanisms for running multiple processes.
You can use it as a base for your own Docker images.
baseimage-amzn is available for pulling from the docker registry!
If you need additional help, please contact us on our support channels or open a GitHub Issue.
baseimage-amzn is inspired by baseimage-docker project. We would like to say thank you to Phusion for providing some good ideas and code. We would also like to say thank you to Amazon Linux Team for providing excellent Amazon Linux Container Image.
Related resources: Website | Slack | Discussion Forum | Twitter | Blog | FAQs
Table of contents
- What's inside the image?
- Using baseimage-amzn as Docker Base Image
- Container administration
- Conclusion
Component | Why is it included? / Remarks |
---|---|
Amazon Linux | The base system. |
A init process | baseimage-amzn comes with an init process. Available as /sbin/my_init . |
rsyslog | Syslog daemon is used by various services and applications to log to /var/log/* files. |
logrotate | Rotates and compresses logs files on a regular basis. |
cron | A cron daemon for cron jobs to run within the container. |
runit | Used for service supervision and management. |
setuser |
A tool for running a command as another user. Sets $HOME correctly. Available as /sbin/setuser . |
ll-user |
Image is configured with ll-user:ll-user unix user and group, and has a UID/GID pair of 500/500. This UID/GID pair maps correctly to ec2-user:ec2-user on Amazon Linux EC2 host. Correct UID/GID mapping between host and container helps avoid permission related issues. |
We do not ship SSH server in our image. For most users we recommend using docker exec
instead.
While it is certainly possible to run SSH server within baseimage-amzn, securing SSH correctly in an operational setting is non-trivial. If your use-case really requires running SSH server within baseimage-amzn, please contact us and we will find a good way to help you.
We would like to give an overview of the version numbering convention that we follow and how that relates to Amazon Linux releases.
Amazon Linux is a rolling distribution. We can think of Amazon Linux as a single river of packages, and images themselves are just snapshots in time. When we run yum update
our package set gets updated to the tip of this flow.
Releases usually occur in March and September. Release version numbers have the form 20YY.MM
, where YY
refers to the year, and MM
refers to the month. For example 2017.03
.
Between major releases, point releases are made by Amazon Linux Team. Point releases have the form 20YY.MM.X
, where X
is the point release number. For example 2017.03.1
.
baseimage-amzn uses version numbering of the form 20YY.MM-00X
, where 00X
is our point release. For example 2017.03-003
.
We will see the form 20YY.MM-00X
used in the documentation below. You can find the list of baseimage-amzn versions here
To look around the image as root
user, run:
docker run --rm -t -i lambdalinux/baseimage-amzn:2017.03-003 /sbin/my_init -- /bin/bash -l
docker run --rm -t -i lambdalinux/baseimage-amzn:<20YY.MM-00X> /sbin/my_init -- /bin/bash -l
To look around the image as ll-user
user, run:
docker run --rm -t -i lambdalinux/baseimage-amzn:2017.03-003 /sbin/my_init -- /sbin/setuser ll-user /bin/bash -l
docker run --rm -t -i lambdalinux/baseimage-amzn:<20YY.MM-00X> /sbin/my_init -- /sbin/setuser ll-user /bin/bash -l
Here <20YY.MM-00X>
is baseimage-amzn version number.
You don't have to download anything manually. The above command will automatically pull baseimage-amzn image from the Docker registry.
The image is called lambdalinux/baseimage-amzn
and is available on the Docker registry.
# Use lambdalinux/baseimage-amzn as base image.
# See https://hub.docker.com/r/lambdalinux/baseimage-amzn/tags/ for
# a list of version numbers.
FROM lambdalinux/baseimage-amzn:<20YY.MM-00X>
# Use baseimage-amzn's init system
CMD ["/sbin/my_init"]
RUN \
# Update RPM packages
yum update && \
# ...put your own build instructions here...
# Clean up YUM when done
yum clean all && \
rm -rf /var/cache/yum/* && \
rm -rf /tmp/* && \
rm -rf /var/tmp/*
We use docker build
command to build our Docker Image.
Once the image is built, we can start our container with docker run
command.
docker run -d <DOCKER_IMAGE>
Since our Dockerfile
includes the instruction CMD ["/sbin/my_init"]
, Docker will start the my_init
process. my_init
will set up our container environment and start runit process supervisor. Runit then launches and manage processes inside our container.
We can run pstree
command within the Docker container to see this behavior in action.
Find the container name of the running Docker container.
docker ps
Execute pstree
command in the container.
docker exec <CONTAINER_NAME> /usr/bin/pstree
my_init---runsvdir-|-runsv---rsyslogd---2*[{rsyslogd}]
`-runsv---crond`
We can stop the running Docker container with docker stop
command.
We can add additional daemons (e.g. our own app) to the image by creating runit entries. We have to write a small shell script which runs our daemon, and runit will keep it running for us, restarting it when it crashes, etc.
Runit requires the shell script to be named run
. It must be an executable, and should be placed in the directory /etc/service/<NAME>
.
Here is an example showing how a memcached server runit entry can be made.
Create a file memcached.sh
. Make sure this file is has execute permission set (chmod +x
).
#!/bin/sh
# `/sbin/setuser memcached` runs the given command as the user `memcached`.
# If you omit that part, the command will be run as root.
exec /sbin/setuser memcached /usr/bin/memcached >> /var/log/memcached.log 2>&1
In Dockerfile
:
RUN mkdir /etc/service/memcached
ADD memcached.sh /etc/service/memcached/run
Note that the daemon being executed by the run
shell script must not put itself into the background and must run in the foreground. Daemons usually have a command line flag or a config file option for running in foreground mode.
The baseimage-amzn init system, /sbin/my_init
, can run scripts during startup. They are run in the following order if they exist.
- All executable scripts in
/etc/my_init.d
. The scripts in this directory are executed in alphabetical order. - The script
/etc/rc.local
.
All scripts must exit correctly, that is with an exit code 0. If any script exits with a non-zero exit code, the booting will fail.
The following example shows us how to add startup script. This script logs the time of boot to the file /tmp/boottime.txt
.
Create a file logtime.sh
. We need to make sure this file has execute permission set (chmod +x
).
#!/bin/sh
date > /tmp/boottime.txt
In Dockerfile
:
RUN mkdir -p /etc/my_init.d
ADD logtime.sh /etc/my_init.d/logtime.sh
When we use /sbin/my_init
as our main container command, any environment variables defined using docker run --env
or the ENV
instruction in the Dockerfile
will be picked up by /sbin/my_init
. These environment variables will be passed to all child processes, including /etc/my_init.d
startup scripts, runit and runit managed services.
Following example shows this in action.
$ docker run --rm -t -i \
--env FOO=bar --env HELLO='my beautiful world' \
lambdalinux/baseimage-amzn:<20YY.MM-00X> /sbin/my_init -- /bin/bash -l
[...]
*** Running /bin/bash -l...
[root@ff6cbb791855] / # echo $FOO
bar
[root@ff6cbb791855] / # echo $HELLO
my beautiful world
[root@ff6cbb791855] / #
Here <20YY.MM-00X>
is baseimage-amzn version number.
When /sbin/my_init
starts up, before running any startup scripts, /sbin/my_init
imports environment variables from the directory /etc/container_environment
. This directory contains files that are named after the environment variable names. The file contents contain the environment variable values.
/etc/container_environment
is a good place to define our environment variables at build time. The environment variables defined in /etc/container_environment
is inherited by all startup scripts and runit services.
For example, here is how we can define an environment variable in our Dockerfile
.
RUN echo Apachai Hopachai > /etc/container_environment/MY_NAME
We can verify that it works, as follows:
$ docker run --rm -t -i \
<DOCKER_IMAGE> /sbin/my_init -- /bin/bash -l
[...]
*** Running /bin/bash -l...
[root@2a3356297ec4] / # echo $MY_NAME
Apachai Hopachai
[root@2a3356297ec4] / #
Certain services such as Nginx, resets the environment variables of its child processes. When this happens, /sbin/my_init
provides a way to query the original environment variables that was passed at the time of container launch.
During startup, right after importing environment variables from /etc/container_environment
, /sbin/my_init
dumps all its environment variables (that is, all variables imported from /etc/container_environment
and variables picked up from docker run --env
) to the following locations.
/etc/container_environment.sh
- Contains the environment variables in bash format. We can source this file from a bash shell script./etc/container_environment.json
- Contains the environment variables in JSON format.
Multiple formats makes it easy to query the original environment variables from our favorite programming/scripting language.
Here is an example showing how this works.
$ docker run --rm -t -i \
--env FOO=bar --env HELLO='my beautiful world' \
lambdalinux/baseimage-amzn:<20YY.MM-00X> /sbin/my_init -- /bin/bash -l
[...]
*** Running /bin/bash -l...
[root@42d4b4cd09b3] / # ls /etc/container_environment
FOO HELLO HOME HOSTNAME LANG LC_CTYPE PATH PS1 TERM
[root@42d4b4cd09b3] / # cat /etc/container_environment/FOO; echo
bar
[root@42d4b4cd09b3] / # cat /etc/container_environment/HELLO; echo
my beautiful world
[root@42d4b4cd09b3] / # cat /etc/container_environment.json; echo
{"LANG": "en_US.UTF-8", "TERM": "xterm", "PS1": "[\\u@\\h] \\w \\$ ", "HOSTNAME": "42d4b4cd09b3", "LC_CTYPE": "en_US.UTF-8", "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HOME": "/", "FOO": "bar", "HELLO": "my beautiful world"}
[root@42d4b4cd09b3] / # source /etc/container_environment.sh
[root@42d4b4cd09b3] / # echo $HELLO
my beautiful world
[root@42d4b4cd09b3] / # ls -la /etc/container_environment.sh
-rw-r----- 1 root docker_env 249 Jun 25 11:02 /etc/container_environment.sh
[root@42d4b4cd09b3] / # ls -la /etc/container_environment.json
-rw-r----- 1 root docker_env 254 Jun 25 11:02 /etc/container_environment.json
Here <20YY.MM-00X>
is baseimage-amzn version number.
/etc/container_environment.sh
and /etc/container_environment.json
files are owned by root and accessible only by the docker_env
group. To read these files as non-root user, we need to add the non-root user to docker_env
group.
Packages can be installed and updated inside the container using yum install
and yum update
commands.
We recommend that including the following in Dockerfile
so that the docker image has the latest packages.
RUN \
yum update && \
yum clean all && \
rm -rf /var/cache/yum/* && \
rm -rf /tmp/* && \
rm -rf /var/tmp/*
When working with containers, we will encounter situations where we may want to run a command inside a container or login to it. This could be for development, debugging or inspection purposes.
This section describes how to run a command inside a new container. To run a command inside an existing container see Running a command inside an existing, running container.
baseimage-amzn provides a facility to run a single one-shot command inside a new container the following way.
docker run <DOCKER_IMAGE> /sbin/my_init -- COMMAND ARGUMENTS ...
This command does the following.
- Runs all system startup files, such as
/etc/my_init.d/*
and/etc/rc.local
. - Starts all runit services.
- Runs the specified command.
- When the specified command exists, stops all runit services.
For example:
$ docker run lambdalinux/baseimage-amzn:<20YY.MM-00X> /sbin/my_init -- /bin/ls
*** Running /etc/rc.local...
*** Booting runit daemon...
*** Runit started as PID 7
*** Running /bin/ls...
bin
boot
[...]
usr
var
*** /bin/ls exited with status 0.
*** Shutting down runit daemon (PID 7)...
*** Killing all processes...
We can customize how /sbin/my_init
is invoked. Run docker run <DOCKER_IMAGE> /sbin/my_init --help
for more information.
The following example runs /bin/ls
without running the startup files, in quite mode, while running all runit services.
$ docker run lambdalinux/baseimage-amzn:<20YY.MM-00X> \
/sbin/my_init --skip-startup-files --quiet -- /bin/ls
bin
boot
[...]
usr
var
Here <20YY.MM-00X>
is baseimage-amzn version number.
Start Docker container:
docker run -d <DOCKER_IMAGE>
Find the container name of the running Docker container.
docker ps
Once we have the container name, we can use docker exec
to run commands in the container. For example, to run echo hello world
:
docker exec <CONTAINER_NAME> /bin/echo hello world
To open a bash session inside a running container, we need to pass -t -i
so that a terminal is available.
docker exec -t -i <CONTAINER_NAME> /bin/bash -l
- Using baseimage-amzn? Tweet about us and follow us on Twitter.
- Having problems? Please contact us on any of our support channels or post a GitHub Issue.
Thank you for using baseimage-amzn.