[Docker]: Building NGINX cookbook in dockerized container

Docker + Chef-solo + Your Cookbooks

The previous example runs nginx stack on ubuntu:14.04 from the recipes obtained from the chef supermarket. The requirements to be downloaded are mentioned in the Berksfile.

So, how do we add custom build recipes?
Let’s build our custom nginx recipe which will be provisioned in docker container using chef-solo.

1. Download chef-dk to your local machine

2. Create the skeleton

|_ Berksfile \
(will specify the dependencies to be downloaded from the supermarket.io > currently we don’t need any, but would still the file for potential use)
|_ solo.rb
|_ solo.json
|_ Dockerfile
|_ cookbooks/ (will contain your cookbooks, initialized using chef commands)

3. Tailor made cookbook – special for you!

chef generate cookbook cookbooks/nginx

At this stage you may want to populate your recipe with necesary commands.

cookbooks/nginx/recipes/default.rb

#
# Cookbook:: nginx
# Recipe:: default
#
# Copyright:: 2017, The Authors, All Rights Reserved.

package ['nginx'] do
  action :install
end

package ['php7.0-fpm'] do
  action :install
end

package ['php-imagick', 'php-curl', 'php-gd', 'php-mcrypt', 'php-xml', 'php-mbstring', 'php-soap', 'php-mysql', 'php-pear'] do
    action :install
end

package ['ntp', 'htop', 'vim'] do
    action :install
end

template '/etc/nginx/sites-enabled/default' do
  source 'default.conf'
end

cookbooks/nginx/templates/default.conf

##

# Default server configuration
#
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    # SSL configuration
    #
    # listen 443 ssl default_server;
    # listen [::]:443 ssl default_server;
    #
    # Note: You should disable gzip for SSL traffic.
    # See: https://bugs.debian.org/773332
    #
    # Read up on ssl_ciphers to ensure a secure configuration.
    # See: https://bugs.debian.org/765782
    #
    # Self signed certs generated by the ssl-cert package
    # Don't use them in a production server!
    #
    # include snippets/snakeoil.conf;

    root /app;

    # Add index.php to the list if you are using PHP
    index index.html index.htm index.nginx-debian.html;

    server_name _;

    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        try_files $uri $uri/ =404;
    }

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;

        # With php7.0-cgi alone:
    #   fastcgi_pass 127.0.0.1:9000;
        # With php7.0-fpm:
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    }

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #   deny all;
    #}
}


# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
#  listen 80;
#  listen [::]:80;
#
#  server_name example.com;
#
#  root /var/www/example.com;
#  index index.html;
#
#  location / {
#      try_files $uri $uri/ =404;
#  }
#}

4. File adjustments for ubuntu:16.04

solo.rb

# Solo.rb
root = File.absolute_path(File.dirname(__FILE__))
file_cache_path root
cookbook_path root + '/cookbooks'

solo.json

{
    "run_list": [
    "recipe[nginx::default]"
    ]
}

Berksfile

#Berksfile
source 'https://supermarket.chef.io'

Dockerfile

FROM ubuntu:16.04
RUN apt-get -y update
RUN apt-get -y install curl build-essential libxml2-dev libxslt-dev git
RUN curl -L https://www.opscode.com/chef/install.sh | bash
RUN echo "gem: --no-ri --no-rdoc" > ~/.gemrc
RUN /opt/chef/embedded/bin/gem install berkshelf

RUN apt-get -y update
RUN apt-get -y install python-software-properties
RUN apt-get -y update

ADD ./Berksfile /Berksfile
ADD ./solo.rb /var/chef/solo.rb
ADD ./solo.json /var/chef/solo.json
ADD ./cookbooks /var/chef/cookbooks

RUN cd / && /opt/chef/embedded/bin/berks vendor /var/chef/cookbooks
RUN chef-solo -c /var/chef/solo.rb -j /var/chef/solo.json

CMD service php7.0-fpm start && nginx -g "daemon off;"

5. Good to go: build, run, enjoy !

in order to experiment the setup I included a www/ directory in the project root with some files. We will mount this directory to the docker container after building our image !

Image is build and stored locally:

docker build -t majdarbash/nginx .

Running our image:

# running our image with default command (CMD will be executed)
docker run -d -p 8080:80 majdarbash/nginx 

# docker run -d -p 8080:80 majdarbash/nginx bash (overriding CMD entry point, to access bash, e.g. troubleshopt)

# running with mounted volume in www (note that nginx will serve from /app based on the chef template above)
docker run -v ~/Developer/docker-chef-solo-skeleton/www:/app -p 8080:80 -d majdarbash/nginx

You can find the full git code on:


https://github.com/majdarbash/docker-chef-solo-skeleton

6. From open-source to open-source

Time to share it back !

Use the following commands to publish your image to the docker hub:

# logged in to docker hub (enter credentials for hub.docker.io)
docker login 

# pushing the image to the repository
docker push majdarbash/nginx

Next time you or someone needs an image, all you need to do is:

docker pull majdarbash/nginx

docker run -v [local_directory]:/app -p 8080:80 -d majdarbash/nginx

Majd Arbash

Leave a Reply