Tool to build and install Docker containers with Chef, Dockerfile and other provisioning tools.
Features:
- Config files are in Ruby.
- Manage complexity of running Docker containers for your environment in one place.
- Manage multiple containers
Other tools:
- docker-composer - with configs in yml
Docker-builder is similar to docker-compose but has some more functionality to customize installation of servers on the host.
Process of installing server in Docker container consists of the following stages:
Process of building and running container on the host machine:
-
Build Docker image
- it will create a Docker image on the host machine
- build using Dockerfile or Chef provisioning
-
Run Docker container
- provision host machine - run scripts locally on the host machine. It can be shell script of Chef recipe
- run container -
docker run
- provision container - run script inside the container. It can be shell script of Chef recipe
-
Install systemd service on the host machine to run Docker container automatically (optional)
-
Start/Stop container
-
Destroy container
-
Destroy image
Concepts of running Docker containers:
- you can rerun containers without losing data. Data is stored on the host machine and shared with container.
Build Docker image:
- from Dockerfile
- Chef provisioning (machine_image)
Provision during installation container on the host machine by:
- running shell script inside container
- running Chef script inside container with Chef provisioning
- Install gem:
gem install docker-builder
We will build and run a simple Docker container with Nginx server.
- install gem
gem install docker-builder
- generate directory structure using generator
docker-builder generate --name=nginx --type=chef
it will create a folder nginx
with necessary directory structure inside.
- in the folder edit config file
config.rb
with common settings
common({
'prefix' => "example-",
'image_prefix' => 'example-',
'dir_data' => '/disk3/data/my-examples/',
})
servers({
'nginx'=>{
# some server options here
},
})
base({
})
- edit custom settings for the server in file
servers/nginx/config.rb
add 'build', {
"image_name" => "nginx",
'build_type' => 'chef',
"base_image" => { "name" => "nginx", "repository" => "nginx", "tag" => "1.10" },
}
add 'install', {
"host" => { 'script_type' => 'chef_recipe', 'script' => 'install_host', },
"node" => { 'script_type' => 'chef_recipe', 'script' => 'install', }
}
add 'docker', {
"command"=> "nginx -g 'daemon off;'",
'ports' => [
[8080,80],
],
'volumes' => [
['html', '/usr/share/nginx/html'],
['log/nginx', '/var/log/nginx/'],
],
'links' => [ ]
}
add 'attributes', {
'nginx' =>{
"sitename" =>"mysite.local"
},
}
- build Docker image
# from the folder with project
docker-builder build
- run container
docker-builder up
- check container is running
docker ps
# see container named example-nginx
- access container
docker exec -ti example-nginx /bin/bash
- access container from browser
http://localhost:8080
Process:
-
Create container - docker create
-
setup network and other settings for container
-
run provision to setup host machine. Script is running on the host machine.
{
'provision'=>{
'setup' => [
{type: 'shell', ..},
..
]
...
}
- run provision to setup created (not running) container. Run script to copy/update files in container.
{
'provision'=>{
'setup'=> [
{type: 'ruby', <<script_options>>},
..
]
...
}
- run container with
docker run
. Specify env variables, hostname and other options - first provision of container - bootstrap script. Run script from inside running container only once. Script should be located inside container.
{
'provision'=>{
'bootstrap'=> [
{type: 'chef', ..},
..
]
}
- provision to initialize container. Run script every time after container starts. Script should be located inside container.
{
'provision'=>{
'init'=> [
{type: 'chef'},
..
]
}
- Use lock file to make sure the container does not start until the provision is finished.
- put scripts in
/path/to/project/ <<server_name>> / scripts / install.sh
Process of building and running container on the host machine:
-
Build Docker image
- it will create a Docker image on the host machine
-
Run Docker container
- provision host machine - run scripts locally on the host machine (recipe install_host.rb)
- run container (docker run)
- provision container - run script in the container (recipe install.rb)
-
Install systemd service to run Docker container (optional)
-
Start/Stop container
-
Destroy container
-
Destroy image
- generate directory structure using generator
docker-builder generate --name=nginx --type=chef
it will create a folder nginx
- in the folder edit config file
config.rb
with common settings
- edit custom settings for the server in file
servers/nginx/config.rb
- build Docker image
# from the folder with project
docker-builder build
- run container
docker-builder up
- check container is running
docker ps
- access container from browser
http://localhost:8080
- Build docker image
cd /path/to/servers
docker-builder build -s server_name
- run docker container
cd /path/to/servers
docker-builder run -s server_name
it will run container.
access container:
docker exec -ti container_name /bin/bash
Run from outside container
'provision' => {
"bootstrap" => [
{'type' => 'shell', 'run_from'=>'host', 'script'=>'name=myserver ruby myprovision1.rb' }
]
}
it will run script name=myserver ruby myprovision1.rb
from the host machine.
- in config file
'provision' => {
"bootstrap" => [
{'type' => 'chef', "script"=>"", "dir_base"=>"/opt/bootstrap", "recipe"=>"server::bootstrap" },
]
},
it will run chef provisioning:
cd /opt/bootstrap/ && chef-client -z -j /opt/bootstrap/config.json --override-runlist "recipe[server::bootstrap]"
config file with attributes (/opt/bootstrap/config.json
) for chef-client is generated automatically.
After checking out the repo, run bin/setup
to install dependencies.
You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
- edit config.rb in your root folder
You can put all settings in this config.rb file and/or use config.rb file in each server's folder.
Config files:
/path/to/project/config.rb
/path/to/project/servers/server1/config.rb
/path/to/project/servers/server2/config.rb
- CHEF_COOKBOOKS - list of paths to chef cookbooks
Build types:
- 'none' - no build required
- 'Dockerfile' - using Dockerfile and docker build command
- 'chef' - using Chef provisioning (gem chef-provisioning-docker)
- 'packer' - using Packer tool
- add additional paths for cookbooks
in folder with servers:
# /path/to/my/servers/.chef/knife.rb
cookbook_path cookbook_path+[
'/path/to/my/cookbooks',
'/path/to/my/other/cookbooks',
]
Example of building Docker container with Chef.
Assume that our server name is 'nginx'.
- edit config file 'myserver/config.rb'
####
-
Chef recipes
-
cookbooks/nginx/recipes/build.rb place chef resources to be included in the Docker image
-
cookbooks/nginx/recipes/install.rb
-
cookbooks/nginx/recipes/install_host.rb
-
build
# run from the folder
docker-builder build['nginx']
- shared data: /disk3/data/server-api/nginx-front
data for nginx server:
-
/etc/nginx/conf.d
-
/var/www/html
-
/var/log/nginx
-
Main site - /var/www/html ==> /disk3/data/server-api/nginx-front/var/www/html
-
Config
- config for server
'build' => {
'build_type' => 'Dockerfile',
"image_name" => "myname",
"base_image" => {} # not used
},
- config for server
'build' => {
'build_type' => 'packer',
"image_name" => "myname",
"base_image" => {
"name" => "nginx",
"repository" => "nginx",
"tag" => "1.10"
},
"packer" => { options for packer }
},
-
options for packer
-
cookbook_paths - list of paths
-
recipe_name
-
examples:
- config for server
'build' => {
'build_type' => 'none',
"image_name" => "myname",
"base_image" => {
"name" => "mysql",
"repository" => "mysql",
"tag" => "3.4.9"
},
},
it will NOT build a new Docker image.
- run recipe install_host which runs on the host machine (not in container)
- run recipe install which runs from within the running container
docker-builder start -s server_name
it starts docker container which was previously created.
Process:
- Start docker container container with
docker start ..
- Provision container
- packer - https://github.com/mitchellh/packer
Packer is a tool for creating machine images for multiple platforms from a single source configuration.
-
run_extra_options
- additional options for docker run command -
hostname
{
..
servers({
'zookeeper'=>{
...
'docker'=> {
...
'run_extra_options'=>'--hostname zookeeper'
}
}
Sometimes you need to clear cache with server info in chef-zero server
docker-builder clear_cache
- commands
docker-builder :up_swarm
docker-builder :destroy_swarm
- config
docker: {
# options here...
}
- swarm_network - network name
- swarm_options - options to pass to docker service create command
prefix for image names, container names, and service names (for swarm mode)
- prefix - common prefix. Added to all names
- container_prefix - prefix for containers
- image_prefix - prefix for images
- service_prefix - prefix for services
Example:
- container name = $prefix$container_prefix$name
prefix='my-'
container_prefix='test-'
container name will be like
my-test-redis
- run script from the host
'provision' => {
"setup" => [
{ 'type' => 'shell', 'script' => 'scripts/mysetup.sh', },
]
},
- it will run the script
scripts/mysetup.sh
- first provision of container
- provision scripts run only once
-
Dockerfile
-
include script /opt/bootstrap/bootstrap.sh in container
ADD scripts/bootstrap.sh /opt/bootstrap/
RUN chmod +x /opt/bootstrap/bootstrap.sh
- config
'provision' => {
"bootstrap" => [
{ 'type' => 'shell', 'script' => '/opt/bootstrap/bootstrap.sh', },
]
},
docker-builder up -s server_name
Process:
- docker create with docker options
- entrypoint: /etc/bootstrap
- generate config with node attributes for chef and save it to temp/boostrap-server.json
- copy config file to container to /opt/bootstrap/config.json
- docker start
- when container starts it runs /etc/bootstrap which
- runs chef-client to provision server first time
- Docker container can be connected to multiple networks. Container has an IP in each network.
Docker networks can be created using docker command docker network create
Docker-builder allows you to manage networks for your container.
- connect to multiple networks and specify default gateway
define IP in each network.
it assumes that networks 'my_bridge1' and 'my_overlay1' exist.
'docker'=> {
..
'network': {
default_gateway: '192.168.1.1',
networks: {
{net: 'bridge'}, # default docker bridge
{net: 'my_bridge1', ip: '10.1.0.12'},
{net: 'my_overlay1', ip: '51.1.0.15'},
}
}
}
in this example container will be connected to three networks: * docker default bridge named 'bridge' * custom docker network named 'my_bridge1' with ip='10.1.0.12' * custom docker network named 'my_overlay1'
create networks:
docker network create --driver bridge --subnet=51.1.0.0/16 --gateway=51.1.0.1 my_bridge1
docker network create -d macvlan --subnet=10.1.0.0/16 --gateway=10.1.0.1 --ip-range=10.1.12.0/24 -o parent=eth0 my_overlay1
see docker networks:
docker network ls
- check
docker exec -ti mycontainer bash
ip route
# sample output
...
- Container will be connected to two networks and NOT connected to default Docker network 'bridge'
'docker'=> {
..
'network': {
networks: {
{net: 'bridge', action: 'remove'}, # remove default docker bridge
{net: 'mybridge1', ip: '10.1.0.12'},
{net: 'my_overlay1', ip: '51.1.0.15'},
}
}
}