diff --git a/README.md b/README.md index c94dc55b..75525455 100644 --- a/README.md +++ b/README.md @@ -20,20 +20,22 @@ If you find this image useful here's how you can help: This image takes all the advantages of [phusion/baseimage-docker](https://github.com/phusion/baseimage-docker) but makes programs optionals to allow more lightweight images and single process images. It also define simple directory structure and files to defined quickly how a program (here called service) is installed, setup and run. So major features are: - - simple way to install services and multiple process image stacks + - simple way to install services and multiple process image stacks (runit, cron, syslog-ng-core and logrotate) - getting environment variables from **.yaml** and **.json** files - special environment files **.yaml.startup** and **.json.startup** deleted after image startup files first execution to keep the image setup secret. +Like in [phusion/baseimage-docker](https://github.com/phusion/baseimage-docker) in a mutliple process container services are supervised by runit and relaunched if they stops. + ## Quick Start ### Image directories structure This image use four directories: -- **/container/environment**: To add environment files. -- **/container/service**: To store services to install, setup and run. -- **/container/service-available**: To store service that may be on demand installed, setup and run. -- **/container/tool**: Contains image tools. +- **/container/environment**: environment files. +- **/container/service**: services to install, setup and run. +- **/container/service-available**: service that may be on demand installed, setup and run. +- **/container/tool**: image tools. By the way at run time an other directoy is create: - **/container/run**: To store container run environment, state, startup files and process to run based on files in /container/environment and /container/service directories. @@ -45,7 +47,7 @@ But we will see that in details right after this quick start. This section define a service directory that can be added in /container/service or /container/service-available. - **my-service**: root directory -- **my-service/install.sh**: Install script (not mandatory). +- **my-service/install.sh**: install script (not mandatory). - **my-service/startup.sh**: startup script to setup the service when the container start (not mandatory). - **my-service/process.sh**: process to run (not mandatory). - **my-service/...** add whatever you need! @@ -63,12 +65,12 @@ First we create the directory structure of the image: - **single-process-image**: root directory - **single-process-image/service**: directory to store the nginx service. - - **single-process-image/environment**: directory to store the default environment files. + - **single-process-image/environment**: environment files directory. - **single-process-image/Dockerfile**: the Dockerfile to build this image. -**service** and **environment** directories name are arbitrary and can be changed but make sure to adapt their name everywhere. +**service** and **environment** directories name are arbitrary and can be changed but make sure to adapt their name in the Dockerfile. -Let's now create the service directory: +Let's now create the nginx service directory: - **single-process-image/service/nginx**: service root directory - **single-process-image/service/nginx/install.sh**: service installation script. @@ -79,20 +81,18 @@ Let's now create the service directory: #### Dockerfile In the Dockerfile we are going to: - - Download nginx. + - Install nginx from apt-get. - Add the service directory to the image. - Install service and clean up. - Add the environment directory to the image. - - Define ports exposed and volumes if needed + - Define ports exposed and volumes if needed. # Use osixia/light-baseimage - # sources: https://github.com/osixia/docker-light-baseimage - FROM osixia/light-baseimage:0.2.1 + # https://github.com/osixia/docker-light-baseimage + FROM osixia/light-baseimage:0.2.1-dev MAINTAINER Your Name - # Download nginx and install cfssl from baseimage - # sources: https://github.com/osixia/docker-light-baseimage/blob/stable/image/tool/install-service-available - #  https://github.com/osixia/docker-light-baseimage/blob/stable/image/service-available/.cfssl/install.sh + # Install nginx RUN apt-get -y update \ && LC_ALL=C DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ nginx @@ -116,7 +116,7 @@ In the Dockerfile we are going to: EXPOSE 80 443 -The Dockerfile contains directives to download nginx from apt-get but all the initial setup will take place in install.sh file (called by /container/tool/install-service tool) for a better build experience. The time consumer download task is decoupled from the initial setup to make great use of docker build cache. If an install.sh file is changed the builder will not have to download again nginx add will just run install scripts. +The Dockerfile contains directives to download nginx from apt-get but all the initial setup will take place in install.sh file (called by /container/tool/install-service tool) for a better build experience. The time consumer download task is decoupled from the initial setup to make great use of docker build cache. If install.sh file is changed the builder won't have to download again nginx add will just run install scripts. #### Service files @@ -141,7 +141,7 @@ Note: The install.sh script is run during the docker build so run time environme This file is used to make process.sh ready to be run and customize the service setup based on run time environment. -For example at run time we would like to introduce ourself so we will use an environment variable WHO_AM_I set by command line with --env. So we add WHO_AM_I value to index.html file but we want to do that only on the first container start because on restart the index.html file will already contains our name: +For example at run time we would like to introduce ourself so we will use an environment variable WHO_AM_I set by command line with --env. So we add WHO_AM_I value to index.html file but we want to do that only on the first container start because on restart the index.html file will already contains our name: #!/bin/bash -e FIRST_START_DONE="${CONTAINER_STATE_DIR}/nginx-first-start-done" @@ -156,7 +156,7 @@ For example at run time we would like to introduce ourself so we will use an env Make sure startup.sh can be executed (chmod +x startup.sh). -As you can see we use CONTAINER_STATE_DIR variable, that define the directory where container state is saved, this variable is automatically set by run tool. Refer to the Advanced User Guide for more information. +As you can see we use CONTAINER_STATE_DIR variable, it contains the directory where container state is saved, this variable is automatically set by run tool. Refer to the Advanced User Guide for more information. ##### process.sh @@ -167,12 +167,12 @@ This file define the command to run: Make sure process.sh can be executed (chmod +x process.sh). -**Caution: The command executed must start a foreground process otherwise the container will immediately stops.** +*Caution: The command executed must start a foreground process otherwise the container will immediately stops.* That why we run nginx with `-g "daemon off;"` That's it we have a single process image that run nginx ! -We could already build this image and test it but before we would like to add a default value to WHO_AM_I if it's not set a run time. +We could already build and test this image but 2 more minutes to take advantage of environment files ! #### Environment files @@ -181,14 +181,15 @@ Let's create two files: - single-process-image/environment/default.yaml.startup ##### default.yaml -Variables defined in this file are available at anytime in the container environment: +In this file we will defined variables that can be used at anytime in the container environment: WHO_AM_I: We are Anonymous. We are Legion. We do not forgive. We do not forget. Expect us. ##### default.yaml.startup -Variables defined in this file are only available during the container **first start** in **startup files**. -This file is deleted right after startup files are processed for the first time, -then all of these values will not be available in the container environment. + +In this file we will defnie variables that are only available during the container **first start** in **startup files**. +\*.yaml.startup are deleted right after startup files are processed for the first time, +then all variables they contains will not be available in the container environment. This helps to keep the container configuration secret. If you don't care all environment variables can be defined in **default.yaml** and everything will work fine. @@ -217,6 +218,7 @@ And **process.sh** to: echo "The secret is: $FIRST_START_SETUP_ONLY_SECRET" exec /usr/sbin/nginx -g "daemon off;" +Ok it's time for the show ! #### Build and test @@ -234,14 +236,18 @@ Inspect the output and you should see that the secret is present in startup scri > The secret is: The bdd password is Baw0unga! And the secret is not defined in the process: +> *** Remove file /container/environment/99-default/default.yaml.startup + +>... + > \*\*\* Running /container/run/process/nginx/run... > The secret is: -In this case it's not really useful to have a secret variable like this, but a concrete example can be found in [osixia/openldap](https://github.com/osixia/docker-openldap) image. -The admin password is available in clear text during the container first start to create a new ldap database where it is saved encrypted. After that the admin password is not available in clear text in the container environment. +Yes in this case it's not really useful to have a secret variable like this, but a concrete example can be found in [osixia/openldap](https://github.com/osixia/docker-openldap) image. +The admin password is available in clear text during the container first start to create a new ldap database where it is saved encrypted. After that the admin password is not available in clear text in the container environment. -Ok let's check our name now, go to http://localhost:8080/ +Ok let's check our name now, go to [http://localhost:8080/](http://localhost:8080/) You should see: > Hi! We are Anonymous. We are Legion. We do not forgive. We do not forget. Expect us. @@ -251,67 +257,66 @@ And finally, let's say who we really are, stop the previous container (ctrl+c) a docker run --env WHO_AM_I="I'm Jon Snow, yes i'm not dead." \ -p 8080:80 example/single-process -Go to http://localhost:8080/ and you should see: +Refresh [http://localhost:8080/](http://localhost:8080/) and you should see: > Hi! I'm Jon Snow, yes i'm not dead. ### Create a multiple process image #### Overview -In this example we will extend the single process image example and add php5-fpm to run php scripts. -We could have copy the single process image example files and add new php5-fpm service files but it's faster, better, stronger ♪ to extends it. +This example takes back the single process image example and add php5-fpm to run php scripts. -So if you don't take a look to the single process image tutorial, it's recommended to do so. - -Also to test this example the `example/single-process` image build from the previous tutorial is needed on the computer. If not you can build it quickly: +See complete example in: [example/multiple-process-image](example/multiple-process-image) - - clone this repo: `git clone https://github.com/osixia/docker-light-baseimage` - - go in **example/single-process-image** and run: `make build` +Note: it would have been ♪ faster, better, stronger ♪ to extends the previous image but to make things easier we just copied files. -First we create the directory structure of the image: +So here the image directory structure: - **multiple-process-image**: root directory - - **multiple-process-image/service**: directory to store the php5-fpm service. + - **multiple-process-image/service**: directory to store the nginx and php5-fpm service. + - **multiple-process-image/environment**: environment files directory. - **multiple-process-image/Dockerfile**: the Dockerfile to build this image. -We won't add environment variable so we don't need the environment directory. +**service** and **environment** directories name are arbitrary and can be changed but make sure to adapt their name in the Dockerfile. + +Let's now create the nginx and php5-fpm directories: -Let's now create the service directory: + - **multiple-process-image/service/nginx**: nginx root directory + - **multiple-process-image/service/nginx/install.sh**: service installation script. + - **multiple-process-image/service/nginx/startup.sh**: startup script to setup the service when the container start. + - **multiple-process-image/service/nginx/process.sh**: process to run. - - **multiple-process-image/service/php5-fpm**: service root directory + - **multiple-process-image/service/php5-fpm**: php5-fpm root directory - **multiple-process-image/service/php5-fpm/install.sh**: service installation script. - **multiple-process-image/service/php5-fpm/process.sh**: process to run. - - **multiple-process-image/service/php5-fpm/config/default**: default nginx server config with php5-fpm. + - **multiple-process-image/service/php5-fpm/config/default**: default nginx server config with -As you can see here we won't need a startup.sh file. - -See complete example in: [example/multiple-process-image](example/multiple-process-image) +Please refer to [single process image](#create-a-single-process-image) for the nginx service files. #### Dockerfile In the Dockerfile we are going to: - - Install the multiple process stack - - Download php5-fpm. + - Install nginx and php5-fpm from apt-get. - Add the service directory to the image. - Install service and clean up. + - Add the environment directory to the image. + - Define ports exposed and volumes if needed. - # Use single process image example - FROM example/single-process + # Use osixia/light-baseimage + # https://github.com/osixia/docker-light-baseimage + FROM osixia/light-baseimage:0.2.1-dev MAINTAINER Your Name - # Install multiple process stack and download php5-fpm - # sources: https://github.com/osixia/docker-light-baseimage/blob/stable/image/tool/install-service-available - #  https://github.com/osixia/docker-light-baseimage/blob/stable/image/service-available/.cfssl/install.sh + # add non free repository to apt-get install multiple process stack, nginx and php5-fpm + # https://github.com/osixia/docker-light-baseimage/blob/stable/image/tool/install-multiple-process-stack RUN echo "deb http://http.debian.net/debian/ jessie main contrib non-free" >> /etc/apt/sources.list \ && apt-get -y update \ && /container/tool/install-multiple-process-stack \ && LC_ALL=C DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + nginx \ php5-fpm # Add service directory to /container/service - # Content : - # /container/service/nginx (from example/single-process) - # /container/service/php5-fpm ADD service /container/service # Use baseimage install-service script and clean all @@ -320,16 +325,28 @@ In the Dockerfile we are going to: && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + # Add default env directory + ADD environment /container/environment/99-default + + # Set /var/www/ in a data volume + VOLUME /var/www/ + + # Expose default http and https ports + EXPOSE 80 443 + -The Dockerfile contains directives to download php5-fpm from apt-get but all the initial setup will take place in install.sh file (called by /container/tool/install-service tool) for a better build experience. The time consumer download task is decoupled from the initial setup to make great use of docker build cache. If an install.sh file is changed the builder will not have to download again php5-fpm add will just run install scripts. +The Dockerfile contains directives to download nginx and php5-fpm from apt-get but all the initial setup will take place in install.sh file (called by /container/tool/install-service tool) for a better build experience. The time consumer download task is decoupled from the initial setup to make great use of docker build cache. If an install.sh file is changed the builder will not have to download again php5-fpm add will just run install scripts. #### Service +Please refer to [single process image](#create-a-single-process-image) for the nginx service files. +Here just php5-fpm files are described. + ##### install.sh This file must only contains directives for the service initial setup. If there is files to download, apt-get command to run we will it takes place in the Dockerfile for a better image building experience (see [Dockerfile](#Dockerfile) ). -In this example, for the initial setup set some php5-fpm default configuration and replace the default nginx server config: +In this example, for the initial setup set some php5-fpm default configuration, replace the default nginx server config and add phpinfo.php file #!/bin/bash -e # this script is run during the image build @@ -343,6 +360,9 @@ In this example, for the initial setup set some php5-fpm default configuration a # replace default website with php5-fpm default website cp -f /container/service/php5-fpm/config/default /etc/nginx/sites-available/default + # create phpinfo.php + echo " /var/www/html/phpinfo.php + Make sure install.sh can be executed (chmod +x install.sh). @@ -355,7 +375,7 @@ This file define the command to run: Make sure process.sh can be executed (chmod +x process.sh). -**Caution: The command executed must start a foreground process otherwise the container will immediately stops.** +*Caution: The command executed must start a foreground process otherwise the container will immediately stops.* That why we run php5-fpm with `--nodaemonize"` @@ -380,13 +400,11 @@ That why we run php5-fpm with `--nodaemonize"` location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; - # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini - # With php5-fpm: fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; include fastcgi_params; - try_files $uri =404; + include fastcgi.conf; } } @@ -395,12 +413,25 @@ That's it we have a multiple process image that run nginx and php5-fpm ! #### Build and test +Build the image: + + docker build -t example/multiple-process --rm . + +Start a new container: + docker run -p 8080:80 example/multiple-process + +Go to http://localhost:8080/phpinfo.php + +> phpinfo should be printed + +So we have a container with two process supervised by runit runing in our container. ### Using service available + ### Real world image example diff --git a/example/multiple-process-image/Dockerfile b/example/multiple-process-image/Dockerfile index 8bd2e6b5..eba93fa7 100644 --- a/example/multiple-process-image/Dockerfile +++ b/example/multiple-process-image/Dockerfile @@ -1,20 +1,18 @@ -# Use single process image example -FROM example/single-process +# Use osixia/light-baseimage +# https://github.com/osixia/docker-light-baseimage +FROM osixia/light-baseimage:0.2.1-dev MAINTAINER Your Name -# Install multiple process stack and download php5-fpm -# sources: https://github.com/osixia/docker-light-baseimage/blob/stable/image/tool/install-service-available -#  https://github.com/osixia/docker-light-baseimage/blob/stable/image/service-available/.cfssl/install.sh +# add non free repository to apt-get install multiple process stack, nginx and php5-fpm +# https://github.com/osixia/docker-light-baseimage/blob/stable/image/tool/install-multiple-process-stack RUN echo "deb http://http.debian.net/debian/ jessie main contrib non-free" >> /etc/apt/sources.list \ && apt-get -y update \ && /container/tool/install-multiple-process-stack \ && LC_ALL=C DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + nginx \ php5-fpm # Add service directory to /container/service -# Content : -# /container/service/nginx (from example/single-process) -# /container/service/php5-fpm ADD service /container/service # Use baseimage install-service script and clean all @@ -22,3 +20,12 @@ ADD service /container/service RUN /container/tool/install-service \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +# Add default env directory +ADD environment /container/environment/99-default + +# Set /var/www/ in a data volume +VOLUME /var/www/ + +# Expose default http and https ports +EXPOSE 80 443 diff --git a/example/multiple-process-image/environment/default.yaml b/example/multiple-process-image/environment/default.yaml new file mode 100644 index 00000000..9986fd0f --- /dev/null +++ b/example/multiple-process-image/environment/default.yaml @@ -0,0 +1,8 @@ +# This is the default image configuration file +# These values will persists in container environment. + +# All environment variables used after the container first start +# must be defined here. +# more information : https://github.com/osixia/docker-light-baseimage + +WHO_AM_I: We are Anonymous. We are Legion. We do not forgive. We do not forget. Expect us. diff --git a/example/multiple-process-image/environment/default.yaml.startup b/example/multiple-process-image/environment/default.yaml.startup new file mode 100644 index 00000000..e381f17f --- /dev/null +++ b/example/multiple-process-image/environment/default.yaml.startup @@ -0,0 +1,9 @@ +# This is the default image startup configuration file +# this file define environment variables used during the container **first start** in **startup files**. + +# This file is deleted right after startup files are processed for the first time, +# after that all these values will not be available in the container environment. +# This helps to keep your container configuration secret. +# more information : https://github.com/osixia/docker-light-baseimage + +FIRST_START_SETUP_ONLY_SECRET: The bdd password is Baw0unga! diff --git a/example/multiple-process-image/service/nginx/install.sh b/example/multiple-process-image/service/nginx/install.sh new file mode 100755 index 00000000..f0fbebac --- /dev/null +++ b/example/multiple-process-image/service/nginx/install.sh @@ -0,0 +1,5 @@ +#!/bin/bash -e +# this script is run during the image build + +rm -rf /var/www/html/index.nginx-debian.html +echo "Hi!" > /var/www/html/index.html diff --git a/example/multiple-process-image/service/nginx/process.sh b/example/multiple-process-image/service/nginx/process.sh new file mode 100755 index 00000000..7afdb388 --- /dev/null +++ b/example/multiple-process-image/service/nginx/process.sh @@ -0,0 +1,3 @@ +#!/bin/bash -e +echo "The secret is: $FIRST_START_SETUP_ONLY_SECRET" +exec /usr/sbin/nginx -g "daemon off;" diff --git a/example/multiple-process-image/service/nginx/startup.sh b/example/multiple-process-image/service/nginx/startup.sh new file mode 100755 index 00000000..20ef1d78 --- /dev/null +++ b/example/multiple-process-image/service/nginx/startup.sh @@ -0,0 +1,12 @@ +#!/bin/bash -e +FIRST_START_DONE="${CONTAINER_STATE_DIR}/nginx-first-start-done" + +# container first start +if [ ! -e "$FIRST_START_DONE" ]; then + echo ${WHO_AM_I} >> /var/www/html/index.html + touch $FIRST_START_DONE +fi + +echo "The secret is: $FIRST_START_SETUP_ONLY_SECRET" + +exit 0 diff --git a/example/multiple-process-image/service/php5-fpm/config/default b/example/multiple-process-image/service/php5-fpm/config/default index 0b2f8015..cc19e0f9 100644 --- a/example/multiple-process-image/service/php5-fpm/config/default +++ b/example/multiple-process-image/service/php5-fpm/config/default @@ -17,12 +17,10 @@ server { location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; - # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini - # With php5-fpm: fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; include fastcgi_params; - try_files $uri =404; + include fastcgi.conf; } } diff --git a/example/multiple-process-image/service/php5-fpm/install.sh b/example/multiple-process-image/service/php5-fpm/install.sh index 39afd32f..25e8737a 100755 --- a/example/multiple-process-image/service/php5-fpm/install.sh +++ b/example/multiple-process-image/service/php5-fpm/install.sh @@ -1,3 +1,6 @@ +#!/bin/bash -e +# this script is run during the image build + # config sed -i --follow-symlinks -e "s/expose_php = On/expose_php = Off/g" /etc/php5/fpm/php.ini sed -i --follow-symlinks -e "s/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/g" /etc/php5/fpm/php.ini @@ -6,3 +9,6 @@ sed -i --follow-symlinks -e "s/;listen.group = www-data/listen.group = www-data/ # replace default website with php5-fpm default website cp -f /container/service/php5-fpm/config/default /etc/nginx/sites-available/default + +# create phpinfo.php +echo " /var/www/html/phpinfo.php diff --git a/example/single-process-image/Dockerfile b/example/single-process-image/Dockerfile index 41f73064..bf9250f0 100644 --- a/example/single-process-image/Dockerfile +++ b/example/single-process-image/Dockerfile @@ -1,11 +1,9 @@ # Use osixia/light-baseimage -# sources: https://github.com/osixia/docker-light-baseimage +# https://github.com/osixia/docker-light-baseimage FROM osixia/light-baseimage:0.2.1-dev MAINTAINER Your Name -# Download nginx and install cfssl from baseimage -# sources: https://github.com/osixia/docker-light-baseimage/blob/stable/image/tool/install-service-available -#  https://github.com/osixia/docker-light-baseimage/blob/stable/image/service-available/.cfssl/install.sh +# Install nginx RUN apt-get -y update \ && LC_ALL=C DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ nginx