šŸ“œ ā¬†ļø ā¬‡ļø

Docker. Best practices on the example of the Oracle xe 11g image



Docker has recently become very popular due to its performance, fault tolerance and, most importantly, simplicity.

Today you can find thousands of images in hub.docker.com . Due to its simplicity in creating images, literally in half an hour you can begin to contribute.
')
But many people forget about the best practices , and due to this docker hub was filled with a huge number of not the best images.

In this article I want to describe how simple and useful it is to create images using Best Practices with an example.

As an example, I chose a non-trivial image with the oracle 11g xe GitHub docker-hub .

In the initial project, you can identify weaknesses and shortcomings, sorted by main points with the best practices:

Use .dockerignore


Very useful functionality, but, unfortunately, many people do not know about it and do not use it.
In this example, by adding exceptions to the .dockerfile, the image build speed has decreased and, most importantly, the image size has become less than more than 2Gb

Of course, it is clear that in git to store heavy binaries is not at all best practice, but for now we’ll miss this moment, as it’s fashionable to say ā€œIt works - don’t touch itā€, or as they like to say in Britain ā€œIt’s historically establishedā€.

As a result, 3 simple lines significantly simplified the image. I also strongly recommend .git to contribute to .dockerignore, since There is a repository stored in this folder, in this case the same copy of large binary files.

oracle-xe_11.2.0-1.0_amd64.debaa oracle-xe_11.2.0-1.0_amd64.debab oracle-xe_11.2.0-1.0_amd64.debac .git .gitignore 


Run only one process per container


This is a fairly common mistake, and is allowed due to the fact that people do not fully understand the principles of work and risks.
First of all, SSHD rushes into the eyes and the CMD instruction is not very correct.
 CMD sed -i -E "s/HOST = [^)]+/HOST = $HOSTNAME/g" /u01/app/oracle/product/11.2.0/xe/network/admin/listener.ora; \ service oracle-xe start; \ /usr/sbin/sshd -D 

The disadvantages of using this approach can be discussed for a very long time, especially if the user wants to ā€œcustomizeā€ the incoming command.

First of all, we delete SSHD because we don’t need it, even if we need to run debug or just connect to the console of the container, it’s better to use docker exec -it $ {CONTAINER_ID} / bin / bash

It is also obvious that when the container is stopped Gracefully, only SSHD stops, while the base itself stops as a process without a parrent from the TERM signal , which is not good, especially for the database, especially for Oracle DB.

by ā€œsedā€ and ā€œservice startā€ it can already be assumed that it simply will not exist, and it will be reasonable to transfer the described functionality to entrypoint.sh

When preparing ENTRYPOINT, I was forced to use several crutches of workarounds (hereafter, a little watered-more correctly). More ENTRYPOINT disassemble a little lower, because he touches several points at once

Minimizing the number of layers


This item is very simple, but at the same time very important, since Docker works on layering incremental changes in the FS one for each instruction, here is an example of rational use, the main thing is to try to keep the code readable and put all changes into one RUN instruction
 # Prepare to install Oracle RUN apt-get update && apt-get install -y -q libaio1 net-tools bc curl && \ apt-get clean && \ rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/* &&\ ln -s /usr/bin/awk /bin/awk &&\ mkdir /var/lock/subsys &&\ chmod 755 /sbin/chkconfig &&\ /oracle-install.sh 

The oracle installation functionality has been moved to the sh script in favor of readability.

Avoid installing unnecessary non-essential packages.


In addition to refusing to install unnecessary packages, it is also extremely important to clean up installation files, caches, etc. in one instruction in order to eliminate unnecessary layers of incremental layers, otherwise the image will be doubly heavy.

 apt-get clean && \ rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/* /download/directory 


The container must be ephemeral


This is one of the most difficult and important moments. The term ā€œEphemeralā€ implies that when the container is started, and then stopped when it is removed, the next launch must be able to continue the work of the previous one with the minimum configuration.

In our case, these are database files (principle of operation as a cold backup) with the possibility of its use when starting a new container.

This approach and Docker allows us to quickly and easily create a backup, instantly roll back and clone the entire database.

It is also important to make the basic parameters as configuration via ENV variables.

In the end, I got this ENTRYPOINT

 #!/bin/bash # Prevent owner issues on mounted folders chown -R oracle:dba /u01/app/oracle rm -f /u01/app/oracle/product ln -s /u01/app/oracle-product /u01/app/oracle/product # Update hostname sed -i -E "s/HOST = [^)]+/HOST = $HOSTNAME/g" /u01/app/oracle/product/11.2.0/xe/network/admin/listener.ora sed -i -E "s/PORT = [^)]+/PORT = 1521/g" /u01/app/oracle/product/11.2.0/xe/network/admin/listener.ora echo "export ORACLE_HOME=/u01/app/oracle/product/11.2.0/xe" > /etc/profile.d/oracle-xe.sh echo "export PATH=\$ORACLE_HOME/bin:\$PATH" >> /etc/profile.d/oracle-xe.sh echo "export ORACLE_SID=XE" >> /etc/profile.d/oracle-xe.sh . /etc/profile case "$1" in '') #Check for mounted database files if [ "$(ls -A /u01/app/oracle/oradata)" ]; then echo "found files in /u01/app/oracle/oradata Using them instead of initial database" echo "XE:$ORACLE_HOME:N" >> /etc/oratab chown oracle:dba /etc/oratab chown 664 /etc/oratab printf "ORACLE_DBENABLED=false\nLISTENER_PORT=1521\nHTTP_PORT=8080\nCONFIGURE_RUN=true\n" > /etc/default/oracle-xe rm -rf /u01/app/oracle-product/11.2.0/xe/dbs ln -s /u01/app/oracle/dbs /u01/app/oracle-product/11.2.0/xe/dbs else echo "Database not initialized. Initializing database." printf "Setting up:\nprocesses=$processes\nsessions=$sessions\ntransactions=$transactions\n" echo "If you want to use different parameters set processes, sessions, transactions env variables and consider this formula:" printf "processes=x\nsessions=x*1.1+5\ntransactions=sessions*1.1\n" mv /u01/app/oracle-product/11.2.0/xe/dbs /u01/app/oracle/dbs ln -s /u01/app/oracle/dbs /u01/app/oracle-product/11.2.0/xe/dbs #Setting up processes, sessions, transactions. sed -i -E "s/processes=[^)]+/processes=$processes/g" /u01/app/oracle/product/11.2.0/xe/config/scripts/init.ora sed -i -E "s/processes=[^)]+/processes=$processes/g" /u01/app/oracle/product/11.2.0/xe/config/scripts/initXETemp.ora sed -i -E "s/sessions=[^)]+/sessions=$sessions/g" /u01/app/oracle/product/11.2.0/xe/config/scripts/init.ora sed -i -E "s/sessions=[^)]+/sessions=$sessions/g" /u01/app/oracle/product/11.2.0/xe/config/scripts/initXETemp.ora sed -i -E "s/transactions=[^)]+/transactions=$transactions/g" /u01/app/oracle/product/11.2.0/xe/config/scripts/init.ora sed -i -E "s/transactions=[^)]+/transactions=$transactions/g" /u01/app/oracle/product/11.2.0/xe/config/scripts/initXETemp.ora printf 8080\\n1521\\noracle\\noracle\\ny\\n | /etc/init.d/oracle-xe configure echo "Database initialized. Please visit http://#containeer:8080/apex to proceed with configuration" fi /etc/init.d/oracle-xe start echo "Database ready to use. Enjoy! ;)" ## ## Workaround for graceful shutdown. oracle... ‿( ́ ̵ _-`)‿ ## while [ "$END" == '' ]; do sleep 1 trap "/etc/init.d/oracle-xe stop && END=1" INT TERM done ;; *) echo "Database is not configured. Please run /etc/init.d/oracle-xe configure if needed." $1 ;; esac 


Summary



As a result, following Best Practices, we received a number of advantages:


The results of the work and the details of solving the problems can be found on github and hub.docker.com

Thanks for attention.

Source: https://habr.com/ru/post/260305/


All Articles