Reputation: 185
Creating Docker images would be a simple task for testing environments. But when it comes to Production implementations, we have to follow best practices to overcome any security and workflow issues.
What are the best practices to create a production ready docker image?
Upvotes: 1
Views: 1166
Reputation: 185
As comprehensively described in Create Production Docker Images in 5 Steps by DevopsAnswers, following steps would be considered as a comprehensive guide to create production ready Docker images.
When creating production Docker images, you should have an extensive understating about Docker best practices.
Step 1: Use light weight Base Docker Images
It's a better idea to use a light weight image rather than using a bulky base image, since the usage of resulting Docker image would be more convenient when it's smaller in size.
If you plan to use Docker at highly critical production systems, where you cannot afford a downtime of a few seconds, then first thing you have to choose is a light weight base image for your custom docker image.
Step 2: Reduce intermediate layers
In a Dockerfile
, every instruction such as FROM
, LABEL
, RUN
, CMD
, ADD
etc. would be adding a new layer to the Docker image. So reducing the usage of same instructions multiple times would be a best practice as it would give you a slightly smaller image.
Step 3: Choose specific versions It’s a good practice to choose specific versions in Docker instructions, because it will keep things nice and steady for a production implementation.
Imagine if we use Ubuntu:latest
as the base image. It will use the currently available latest Ubuntu image for our custom Docker image. Additionally, we will setup all the software components based on the same Ubuntu version.
When Ubuntu update the latest tag with a newer base image in Docker Hub, then you might experience some package dependency issues or incompatibilities in your production Docker image.
In addition, we should always try to install the specific package versions rather than installing the general package.
Example
Recommended apt-get install mysql-server-5.5
NOT recommended apt-get install mysql-server
Step 4: Do not include sensitive data
Using sensitive data such as Database credentials and API keys would be a challenging task in Docker.
Do not hard code any login credentials within a Docker image
To overcome this limitation, you should use environment variables effectively.
For example, if you create a Drupal image connecting to a Mysql DB, we can keep the Drupal MySQL DB settings blank as below.
$databases = array (
'default' =>
array (
'default' =>
array (
'database' => '',
'username' => '',
'password' => '',
'host' => '',
'port' => '',
'driver' => 'mysql',
'prefix' => '',
),
),
);
Now we can use ENTRYPOINT
to leverage environment variables to replace Drupal MySQL DB credentials in runtime as below.
#!/bin/sh
set -e
# Apache gets grumpy about PID files pre-existing
rm -f /var/run/apache2.pid
# Define Drupal home file path
DRUPAL_HOME="/var/www/html"
# Define Drupal settings file path
DRUPAL_SETTINGS_FILE="${DRUPAL_HOME}/sites/default/settings.php"
# Check the avilability of environment variables
if [ -n "$DRUPAL_MYSQL_DB" ] && [ -n "$DRUPAL_MYSQL_USER" ] && [ -n "$DRUPAL_MYSQL_PASS" ] && [ -n "$DRUPAL_MYSQL_HOST" ] ; then
echo "Setting up Mysql DB in $DRUPAL_SETTINGS_FILE"
# Set Database
sed -i "s/'database' *=> *''/'database' => '"$DRUPAL_MYSQL_DB"'/g" $DRUPAL_SETTINGS_FILE
# Set Mysql username
sed -i "s/'username' *=> *''/'username' => '"$DRUPAL_MYSQL_USER"'/g" $DRUPAL_SETTINGS_FILE
# Set Mysql password
sed -i "s/'password' *=> *''/'password' => '"$DRUPAL_MYSQL_PASS"'/g" $DRUPAL_SETTINGS_FILE
# Set Mysql host
sed -i "s/'host' *=> *''/'host' => '"$DRUPAL_MYSQL_HOST"'/g" $DRUPAL_SETTINGS_FILE
fi
# Start Apache in foreground
tail -F /var/log/apache2/* &
exec /usr/sbin/apache2ctl -D FOREGROUND
Finally, you can simply define the environment variables during the Docker runtime like below.
docker run -d -t -i
-e DRUPAL_MYSQL_DB='database'
-e DRUPAL_MYSQL_USER='user'
-e DRUPAL_MYSQL_PASS='password'
-e DRUPAL_MYSQL_HOST='host'
-p 80:80
-p 443:443
--name <container name>
<custom image>
Step 5: Run CMD/Entypoint from a non-privileged user
It’s always a good choice to run production systems using a non-privileged user, which is better from security perspectives as well.
You can simply put USER
entry before CMD
or ENTRYPOINT
in Dockerfile as follows.
# Set running user of ENTRYPOINT
USER www-data
# Start entrypoint
ENTRYPOINT ["entrypoint"]
Upvotes: 3