Rumesh Bandara
Rumesh Bandara

Reputation: 185

How to create Production ready Docker images using best practices?

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

Answers (1)

Rumesh Bandara
Rumesh Bandara

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

Related Questions