baha 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +15 -0
- data/.travis.yml +11 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +156 -0
- data/Rakefile +21 -0
- data/baha.gemspec +31 -0
- data/bin/baha +5 -0
- data/example/.gitignore +1 -0
- data/example/base/init.sh.erb +11 -0
- data/example/base/test-template.erb +22 -0
- data/example/example.yml +54 -0
- data/example/rvm/image.yml +33 -0
- data/example/rvm/init.sh.erb +12 -0
- data/lib/baha/builder.rb +130 -0
- data/lib/baha/cli.rb +69 -0
- data/lib/baha/config.rb +142 -0
- data/lib/baha/container_options/cmd.rb +33 -0
- data/lib/baha/container_options/entrypoint.rb +10 -0
- data/lib/baha/container_options/env.rb +21 -0
- data/lib/baha/container_options/exposed_ports.rb +35 -0
- data/lib/baha/container_options/invalid_option_error.rb +15 -0
- data/lib/baha/container_options/option.rb +59 -0
- data/lib/baha/container_options/volumes.rb +24 -0
- data/lib/baha/container_options.rb +38 -0
- data/lib/baha/image.rb +154 -0
- data/lib/baha/log.rb +80 -0
- data/lib/baha/pre_build/command.rb +51 -0
- data/lib/baha/pre_build/download.rb +28 -0
- data/lib/baha/pre_build/template.rb +48 -0
- data/lib/baha/pre_build.rb +47 -0
- data/lib/baha/version.rb +3 -0
- data/lib/baha/workspace.rb +13 -0
- data/lib/baha.rb +5 -0
- data/spec/builder_spec.rb +103 -0
- data/spec/config_spec.rb +93 -0
- data/spec/container_options/cmd_spec.rb +46 -0
- data/spec/container_options/entrypoint_spec.rb +32 -0
- data/spec/container_options/env_spec.rb +26 -0
- data/spec/container_options/exposed_ports_spec.rb +32 -0
- data/spec/container_options/option_spec.rb +43 -0
- data/spec/container_options/volumes_spec.rb +25 -0
- data/spec/fixtures/base_image.yml +5 -0
- data/spec/fixtures/config_build.yml +12 -0
- data/spec/fixtures/config_build_image.yml +10 -0
- data/spec/fixtures/config_eachimage.yml +12 -0
- data/spec/fixtures/config_embedded.yml +11 -0
- data/spec/fixtures/config_include.yml +7 -0
- data/spec/fixtures/config_ssl.yml +13 -0
- data/spec/fixtures/config_sslpath.yml +11 -0
- data/spec/helpers/docker_helpers.rb +31 -0
- data/spec/image_spec.rb +167 -0
- data/spec/log_spec.rb +89 -0
- data/spec/options_spec.rb +52 -0
- data/spec/pre_build/command_spec.rb +69 -0
- data/spec/pre_build/download_spec.rb +43 -0
- data/spec/pre_build/template_spec.rb +55 -0
- data/spec/pre_build_spec.rb +29 -0
- data/spec/spec_helper.rb +39 -0
- metadata +255 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
M2E1OWQwZWYyYmQxMzc3NmM1ZjAzZGI3ZTA5NmM3NGQyYTBjZGIyOA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YWJhZDkxNDNhYmNhMmYyMTBiZDNmNzliYTc2YmNmYTk4M2JmYTlmNQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MmVhNjgyMWFmOTJjZGRiYzE0Zjc1ZjdkOTBiZTlkY2YzYzhhMWRkN2I2ODdl
|
10
|
+
MzQ3N2IwMzhkMDQyNDJiZjU4ZjNmYWZkNzU3YjE0OWE3OThjNTkxZjQwMDZl
|
11
|
+
MDA2Zjg2ZTRhZjg2M2MwODZhNGRmMDM1ZjUwYmJhMDA1Y2E1ZGI=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MTJhOGNiYmYwOGI0YmE5NDI3Y2EwODFiZDU5MzNjYzE4ZmI4NTA0YTlkN2M0
|
14
|
+
ZTgxNmQ5Mzc1ZmZlM2M5NzJiNDg2YjkzYjdmZDlkNjkwYjA5NGUzNzE3YTQz
|
15
|
+
NGVkMTkzYTJhMzgwNGQwMDFjYzNlMWE2YzA1ZjdlZDZjYmJkMTk=
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Justen Walker
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
Baha
|
2
|
+
=======
|
3
|
+
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/baha.png)](http://badge.fury.io/rb/baha)
|
5
|
+
[![Build Status](https://travis-ci.org/justenwalker/baha.png?branch=master)](https://travis-ci.org/justenwalker/baha)
|
6
|
+
|
7
|
+
Introduction
|
8
|
+
------------
|
9
|
+
|
10
|
+
Baha is a command-line utility that assists in the creation of docker images.
|
11
|
+
It addresses some of `Dockerfile`'s' shortcomings and encourages smaller, reusable, tagged images.
|
12
|
+
|
13
|
+
Why not Dockerfiles?
|
14
|
+
--------------------
|
15
|
+
|
16
|
+
Dockerfiles are simple. They are an easy way to make a docker image without needing any other dependencies. However, their simplicity comes at a cost: redundancy. This redundancy is present in a few ways that make more complicated images difficult to make and maintain.
|
17
|
+
|
18
|
+
So why would I use Baha?
|
19
|
+
------------------------
|
20
|
+
|
21
|
+
### 1. Baha forbids more than 1 layer per image
|
22
|
+
|
23
|
+
If you split statements across multiple RUN statements, each of these results in a new layer.
|
24
|
+
The more commands you run, the more layers you create. If you want to *minimize the number of layers* (See [Official Recommendations](https://docs.docker.com/articles/dockerfile_best-practices/))
|
25
|
+
then you must ensure that all statements can be condensed into one line - sacrificing maintainability in the process.
|
26
|
+
|
27
|
+
Baha encourages using scripts instead of `RUN` statements to ensure that only one layer is created per image.
|
28
|
+
|
29
|
+
### 2. Baha encourages smaller images
|
30
|
+
|
31
|
+
The nature of the way the dockerfiles are processed means that each command you run commits a new image.
|
32
|
+
This means, that if you have a `RUN` statement that downloads packages for installation.
|
33
|
+
This will commit a layer with the installation files. Later on if you clean up these files with further RUN commands, they will still exist in your image lineage - thus having no space savings. Without proper precautions, you'll end up having unnecessarily large images.
|
34
|
+
|
35
|
+
Baha ensures that all setup tasks happen in a single commit - so you can write cleanup statements and be assured that they will indeed be absent in the resulting images.
|
36
|
+
|
37
|
+
### 3. Baha understands the bigger picture
|
38
|
+
|
39
|
+
Another best practice (2, #7) recommends that you use your own base image.
|
40
|
+
Dockerfiles make it simple to create your own 'base' image, but how about updates?
|
41
|
+
|
42
|
+
If you were to just rebuild all of your Dockerfiles, you would create an entirely new tree - even if nothing changed.
|
43
|
+
|
44
|
+
Baha will rebuild your entire lineage if the base images changes, but will not rebuild base images if only the children change.
|
45
|
+
|
46
|
+
**Caveat**:
|
47
|
+
|
48
|
+
Baha relies on tagging your releases, noticing when the tag has changed, and treating tags as immutable.
|
49
|
+
This is analogous to how **git** treats tags.
|
50
|
+
|
51
|
+
Tagging your images is another best-practice (2, #5) anyway, so this is encouraged by design.
|
52
|
+
|
53
|
+
Bottom line is: If you change your image, you should change the tag/version.
|
54
|
+
|
55
|
+
#### 4. Baha lets you cache build dependencies
|
56
|
+
|
57
|
+
Most of the time, dependencies are downloaded and installed in the context of the docker container itself.
|
58
|
+
This means that rebuilding an image results in redundant downloads if files haven't changed.
|
59
|
+
|
60
|
+
Baha has pre-build steps that can be used to download files and prepare scripts on host machine.
|
61
|
+
This workspace is made available to the image via a bind mount during build-time. Not only do these dependencies stick around between builds, but they do not need to be cleaned up after the image is committed, since they are never persisted to the container.
|
62
|
+
|
63
|
+
**References**
|
64
|
+
|
65
|
+
1. [Official Dockerfile Best Practices](https://docs.docker.com/articles/dockerfile_best-practices/)<a name="r1"></a>
|
66
|
+
2. [Dockerfile Best Practices - take 2, by Michael Crosby](http://crosbymichael.com/dockerfile-best-practices-take-2.html)<a name="r2"></a>
|
67
|
+
|
68
|
+
Disclaimer
|
69
|
+
----------
|
70
|
+
|
71
|
+
This gem was just released (pre 1.0) and is not ready for production use yet.
|
72
|
+
|
73
|
+
During pre 1.0, things may change that break backwards compatibility between releases. Most likely these breaking
|
74
|
+
changes would be related to the YAML file syntax.
|
75
|
+
|
76
|
+
To Do
|
77
|
+
-----
|
78
|
+
See the [Issue Tracker](https://github.com/justenwalker/baha/issues)
|
79
|
+
|
80
|
+
Installation
|
81
|
+
------------
|
82
|
+
|
83
|
+
```
|
84
|
+
$ gem install baha
|
85
|
+
```
|
86
|
+
### gem install baha
|
87
|
+
|
88
|
+
Usage
|
89
|
+
-----
|
90
|
+
|
91
|
+
```
|
92
|
+
Baha Commands:
|
93
|
+
baha build [options] CONFIG # Builds all docker images based on the given config
|
94
|
+
baha help [COMMAND] # Describe available commands or one specific command
|
95
|
+
baha version # Print version and exit
|
96
|
+
```
|
97
|
+
|
98
|
+
**build**
|
99
|
+
|
100
|
+
```
|
101
|
+
Usage:
|
102
|
+
baha build [options] CONFIG
|
103
|
+
|
104
|
+
Options:
|
105
|
+
[--logfile=LOGFILE] # Log output to LOGFILE. Omit to log to stdout.
|
106
|
+
d, [--debug], [--no-debug] # Toggle debug logging. Includes verbose.
|
107
|
+
v, [--verbose], [--no-verbose] # Toggle verbose logging
|
108
|
+
q, [--quiet], [--no-quiet] # Suppress all logging
|
109
|
+
|
110
|
+
Description:
|
111
|
+
Reads the CONFIG file and builds all of the docker images in the order they appear.
|
112
|
+
```
|
113
|
+
|
114
|
+
Check out the `example` directory for a sample CONFIG file.
|
115
|
+
|
116
|
+
How it works
|
117
|
+
------------
|
118
|
+
|
119
|
+
Baha will read a config.yml file first and load each image configuration.
|
120
|
+
It will build each image in the order they appear by doing the following.
|
121
|
+
|
122
|
+
### Check if the image needs updating
|
123
|
+
1. Check to see if the parent image changed
|
124
|
+
2. Check to see if the tag does not exist in the repository
|
125
|
+
|
126
|
+
### Prepare the image's workspace (bind mount)
|
127
|
+
1. Create the workspace directory if it doesn't exist
|
128
|
+
2. Run any `pre_build` tasks to prepare dependencies
|
129
|
+
|
130
|
+
### Run the image's `command` inside the image
|
131
|
+
1. Creates a new container and runs it with the `command` given
|
132
|
+
2. Commits the container with the run options specified in the images `config` section.
|
133
|
+
|
134
|
+
How to Contribute
|
135
|
+
-----------------
|
136
|
+
|
137
|
+
### Running the tests
|
138
|
+
|
139
|
+
$ bundle
|
140
|
+
$ bundle exec rake spec
|
141
|
+
|
142
|
+
### Installing locally
|
143
|
+
|
144
|
+
$ bundle
|
145
|
+
$ [bundle exec] rake install
|
146
|
+
|
147
|
+
### Reporting Issues
|
148
|
+
|
149
|
+
Please include a reproducible test case.
|
150
|
+
|
151
|
+
License
|
152
|
+
-------
|
153
|
+
|
154
|
+
Copyright (c) 2014 Justen Walker.
|
155
|
+
|
156
|
+
Released under the terms of the MIT License. For further information, please see the file `LICENSE.md`.
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rake/clean'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
require 'rake/clean'
|
6
|
+
CLEAN.include('pkg/', 'example/workspace')
|
7
|
+
CLOBBER.include('Gemfile.lock')
|
8
|
+
|
9
|
+
RSpec::Core::RakeTask.new('spec')
|
10
|
+
|
11
|
+
desc "Run example baha build"
|
12
|
+
task :example do
|
13
|
+
require 'pathname'
|
14
|
+
exampleyml = (Pathname.pwd + 'example' + 'example.yml')
|
15
|
+
puts "Running: baha build -d #{exampleyml}"
|
16
|
+
sh('baha', 'build', '-d', exampleyml.to_s)
|
17
|
+
end
|
18
|
+
|
19
|
+
task :default do
|
20
|
+
sh %{rake -T}
|
21
|
+
end
|
data/baha.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'baha/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "baha"
|
8
|
+
spec.version = Baha::VERSION
|
9
|
+
spec.authors = ["Justen Walker"]
|
10
|
+
spec.email = ["justen.walker+github@gmail.com"]
|
11
|
+
spec.summary = %q{Baha - A tool for describing image builds for Docker}
|
12
|
+
spec.description = %q{Baha - A tool for describing image builds for Docker}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'thor', '~> 0.19.1'
|
22
|
+
spec.add_dependency 'docker-api', '~> 1.14.0'
|
23
|
+
spec.add_dependency 'json', '~> 1.8.1'
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.7'
|
26
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
27
|
+
spec.add_development_dependency 'rspec', '~> 3.1.0'
|
28
|
+
spec.add_development_dependency 'rspec-mocks', '~> 3.1.3'
|
29
|
+
spec.add_development_dependency 'rspec-its', '~> 1.1.0'
|
30
|
+
spec.add_development_dependency 'simplecov', '~> 0.9.1'
|
31
|
+
end
|
data/bin/baha
ADDED
data/example/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
workspace/
|
@@ -0,0 +1,22 @@
|
|
1
|
+
### This is the parent image config
|
2
|
+
parent: <%= parent %>
|
3
|
+
|
4
|
+
### This is the maintainer of the image
|
5
|
+
maintainer: <%= maintainer %>
|
6
|
+
|
7
|
+
### This is the bind location for the workspace
|
8
|
+
bind: <%= bind %>
|
9
|
+
|
10
|
+
### This is the location of the workspace on the host machine
|
11
|
+
workspace: <%= workspace %>
|
12
|
+
|
13
|
+
### This is the image name
|
14
|
+
name: <%= name %>
|
15
|
+
|
16
|
+
### This is the target tag/version
|
17
|
+
tag: <%= tag %>
|
18
|
+
|
19
|
+
### The render function will render other files
|
20
|
+
### START RENDER ###
|
21
|
+
include: <%= render "init.sh.erb" %>
|
22
|
+
### END RENDER ###
|
data/example/example.yml
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
---
|
2
|
+
### Docker URL. Default is unix:///var/run/docker.sock
|
3
|
+
### You can also run Baha with the env variable:
|
4
|
+
### DOCKER_HOST=tcp://192.168.59.103:2376
|
5
|
+
# docker_url: tcp://192.168.59.103:2376
|
6
|
+
#
|
7
|
+
defaults:
|
8
|
+
### If an image doesn't have a parent, it will default to this one.
|
9
|
+
parent: ubuntu:14.04.1
|
10
|
+
### When tagging an image, the name will be tagged with: {repository}/{name}
|
11
|
+
repository: docker.example.com/baha
|
12
|
+
### Put your name and email here to claim authorship
|
13
|
+
maintainer: Ishmael <ishmael@example.com>
|
14
|
+
### By default, the image's workspace will be mounted here inside the container
|
15
|
+
bind: '/.data'
|
16
|
+
### If your docker is configured for SSL connections
|
17
|
+
### You should supply the options here.
|
18
|
+
###
|
19
|
+
### ENV variables take precedence over the ssl config
|
20
|
+
### - DOCKER_CERT_PATH and DOCKER_TLS_VERIFY=1
|
21
|
+
###
|
22
|
+
### Leave this out if your docker connection is insecure (http or unix socket)
|
23
|
+
### Having an ssl config assumes the connection is https://
|
24
|
+
### having a unix socket assumes the connection is insecure, this section would be ignored
|
25
|
+
ssl:
|
26
|
+
### Path to certificates and key
|
27
|
+
### Assumes the files are: ca.pem, cert.pem, and key.pem
|
28
|
+
### Same as specifying DOCKER_CERT_PATH=~/.boot2docker/certs/boot2docker-vm
|
29
|
+
# cert_path: ~/.boot2docker/certs/boot2docker-vm
|
30
|
+
#
|
31
|
+
### You can also specify them individually:
|
32
|
+
# cert: ~/.boot2docker/certs/boot2docker-vm/cert.pem
|
33
|
+
# key: ~/.boot2docker/certs/boot2docker-vm/key.pem
|
34
|
+
# ca: ~/.boot2docker/certs/boot2docker-vm/ca.pem
|
35
|
+
#
|
36
|
+
### Verify docker host's certificate chain
|
37
|
+
verify: true
|
38
|
+
### Each image is an element of the images array
|
39
|
+
### The images will be built in the order they appear
|
40
|
+
images:
|
41
|
+
- name: base
|
42
|
+
tag: 1.0.0 # Tag your image with a version. If the version changes, the image will be rebuilt
|
43
|
+
### This list of tasks will be executed in order *before* the image container is built.
|
44
|
+
### It is meant to prepare the workspace by downloading and creating scripts to be run in the context of the container.
|
45
|
+
pre_build:
|
46
|
+
### The template module copies/processes an ERB into the image's workspace folder
|
47
|
+
- { template: 'base/init.sh.erb', dest: 'init.sh' }
|
48
|
+
### This template shows the available bindings
|
49
|
+
- { template: 'base/test-template.erb', dest: 'test.txt' }
|
50
|
+
command: ['/bin/bash','/.data/init.sh']
|
51
|
+
### Instead of listing all of the image configs in the same file, you can
|
52
|
+
### include them from another file relative to this config.
|
53
|
+
### Keep things modular and maintainable.
|
54
|
+
- include: rvm/image.yml
|
@@ -0,0 +1,33 @@
|
|
1
|
+
### Base on another image created before me
|
2
|
+
parent: base:1.0.0
|
3
|
+
name: rvm-test
|
4
|
+
tag: 1.9.3
|
5
|
+
### Override default maintainer
|
6
|
+
maintainer: '"Captain Ahab" <ahab@example.com>'
|
7
|
+
### Override default bind mount
|
8
|
+
bind: '/.rvm'
|
9
|
+
pre_build:
|
10
|
+
- { download: 'https://get.rvm.io', file: 'rvm.sh' }
|
11
|
+
- { template: 'rvm/init.sh.erb', dest: 'init.sh' }
|
12
|
+
command: ['/bin/bash','/.rvm/init.sh']
|
13
|
+
### Specify container's run configuration here
|
14
|
+
config:
|
15
|
+
### Takes an array of port numbers (assumes tcp)
|
16
|
+
### Can also be in the form 9000/udp to expose UDP ports
|
17
|
+
exposedports:
|
18
|
+
- 8080
|
19
|
+
### Register volumes. Each array item should be a path
|
20
|
+
volumes:
|
21
|
+
- '/logs'
|
22
|
+
### Environment variables. Hash of KEY=VALUE pairs
|
23
|
+
env:
|
24
|
+
HOME: '/root'
|
25
|
+
### Entrypoint command. Should just be 1 string
|
26
|
+
entrypoint: '/bin/bash'
|
27
|
+
### Override the docker containers hostname
|
28
|
+
hostname: 'my.hostname.docker'
|
29
|
+
### Override the internal username executing the command
|
30
|
+
user: 'root'
|
31
|
+
### Options coming after the entrypoint
|
32
|
+
cmd:
|
33
|
+
- '-l'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
#! /bin/bash
|
2
|
+
|
3
|
+
## Install RVM
|
4
|
+
gpg --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3
|
5
|
+
/bin/bash /.rvm/rvm.sh stable || exit 2
|
6
|
+
source /etc/profile.d/rvm.sh
|
7
|
+
rvm install 1.9.3
|
8
|
+
|
9
|
+
## Clean up
|
10
|
+
apt-get autoremove -y
|
11
|
+
apt-get clean
|
12
|
+
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
data/lib/baha/builder.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'baha/config'
|
2
|
+
require 'baha/image'
|
3
|
+
require 'baha/log'
|
4
|
+
require 'baha/pre_build'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
class Baha::Builder
|
8
|
+
LOG = Baha::Log.for_name("Builder")
|
9
|
+
|
10
|
+
class BuildError < RuntimeError
|
11
|
+
attr_reader :image, :status
|
12
|
+
def initialize(status,image)
|
13
|
+
super("Unable to build image : #{image.name} -- Status: #{status.inspect}")
|
14
|
+
@image = image
|
15
|
+
@status = status
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :config
|
20
|
+
|
21
|
+
def initialize(config)
|
22
|
+
@config = case config
|
23
|
+
when Baha::Config
|
24
|
+
config
|
25
|
+
else
|
26
|
+
Baha::Config.load(config.to_s)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def build!
|
31
|
+
LOG.info("Building Images")
|
32
|
+
LOG.debug { "Config: #{@config.inspect}" }
|
33
|
+
LOG.debug { "Initializing Docker" }
|
34
|
+
@config.init_docker!
|
35
|
+
|
36
|
+
@config.each_image do |image|
|
37
|
+
build_log = Baha::Log.for_name("Builder [#{image.name}]")
|
38
|
+
unless image.needs_update?
|
39
|
+
build_log.info { "Skipped image #{image.name} - No update needed" }
|
40
|
+
next
|
41
|
+
end
|
42
|
+
|
43
|
+
## Prepare Workspace
|
44
|
+
workspace = Pathname.new(@config.workspace) + image.name
|
45
|
+
unless workspace.exist?
|
46
|
+
build_log.debug { "Creating Workspace: #{workspace}" }
|
47
|
+
FileUtils.mkdir_p workspace.to_s
|
48
|
+
end
|
49
|
+
|
50
|
+
## Pre-Build tasks
|
51
|
+
build_log.info { "Building #{image.name}" }
|
52
|
+
if image.pre_build
|
53
|
+
build_log.debug { "Preparing workspace for #{image.name}" }
|
54
|
+
image.pre_build.each do |task|
|
55
|
+
build_log.debug { "execute task: #{task.inspect}" }
|
56
|
+
Baha::PreBuild::Module.execute(task.merge({ :config => @config, :image => image }))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
## Build Image
|
61
|
+
container_config = {
|
62
|
+
'Image' => image.parent_id,
|
63
|
+
'Cmd' => image.command,
|
64
|
+
'Workingdir' => image.bind
|
65
|
+
}
|
66
|
+
build_log.debug { "Creating container for #{image.name} => #{container_config.inspect}" }
|
67
|
+
container = Docker::Container.create(container_config)
|
68
|
+
build_log.debug { "Created container #{container.id} "}
|
69
|
+
|
70
|
+
build_log.debug { "Running container for #{image.name}" }
|
71
|
+
container.start({
|
72
|
+
'Binds' => "#{image.workspace.expand_path}:#{image.bind}"
|
73
|
+
})
|
74
|
+
|
75
|
+
begin
|
76
|
+
## Stream logs
|
77
|
+
container.streaming_logs({'stdout' => true, 'stderr' => true, 'follow' => true, 'timestamps' => false }) do |out,msg|
|
78
|
+
case out
|
79
|
+
when :stdout
|
80
|
+
build_log.info { "++ #{msg.chomp}" }
|
81
|
+
when :stderr
|
82
|
+
build_log.warn { "++ #{msg.chomp}" }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
## Wait for finish
|
86
|
+
build_log.debug { "Waiting #{image.timeout} seconds for container #{container.id} to finish building" }
|
87
|
+
status = container.wait(image.timeout)
|
88
|
+
rescue Exception => e
|
89
|
+
build_log.error { "Error building image #{image.name}" }
|
90
|
+
build_log.error { e }
|
91
|
+
build_log.info { "Removing container #{container.id}" }
|
92
|
+
container.stop
|
93
|
+
container.remove
|
94
|
+
raise BuildError.new("Interrupted",image)
|
95
|
+
end
|
96
|
+
|
97
|
+
if status['StatusCode'] != 0
|
98
|
+
build_log.error { "Error building image #{image.name}" }
|
99
|
+
build_log.info { "Removing container #{container.id}" }
|
100
|
+
container.remove
|
101
|
+
raise BuildError.new(status,image)
|
102
|
+
end
|
103
|
+
|
104
|
+
## Commit Image
|
105
|
+
build_log.debug { "Committing Container #{container.id}" }
|
106
|
+
build_log.debug { "Run Config: #{image.commit_config}" }
|
107
|
+
build_image = container.commit({'run'=>image.commit_config})
|
108
|
+
|
109
|
+
build_log.info { "New Image created: #{build_image.id}"}
|
110
|
+
build_image = Docker::Image.get(build_image.id)
|
111
|
+
|
112
|
+
image.tags.each do |tag|
|
113
|
+
build_log.debug { "Tagging as #{tag}"}
|
114
|
+
t = tag.split(/:/)
|
115
|
+
build_image.tag(:repo => t[0], :tag => t[1])
|
116
|
+
end
|
117
|
+
|
118
|
+
## Cleanup container
|
119
|
+
container.remove
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def inspect
|
124
|
+
<<-eos.gsub(/\n?\s{2,}/,'')
|
125
|
+
#{self.class.name}<
|
126
|
+
@config=#{@config.inspect}
|
127
|
+
>
|
128
|
+
eos
|
129
|
+
end
|
130
|
+
end
|
data/lib/baha/cli.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'baha/builder'
|
3
|
+
require 'baha/log'
|
4
|
+
|
5
|
+
class Baha::CLI < Thor
|
6
|
+
desc "build [options] CONFIG", "Builds all docker images based on the given config"
|
7
|
+
long_desc <<-LONGDESC
|
8
|
+
Reads the CONFIG file and builds all of the docker images in the order they appear.
|
9
|
+
LONGDESC
|
10
|
+
option :logfile, {
|
11
|
+
:required => false,
|
12
|
+
:type => :string,
|
13
|
+
:desc => "Log output to LOGFILE. Omit to log to stdout."
|
14
|
+
}
|
15
|
+
option :debug, {
|
16
|
+
:aliases => :d,
|
17
|
+
:required => false,
|
18
|
+
:type => :boolean,
|
19
|
+
:default => false,
|
20
|
+
:desc => 'Toggle debug logging. Includes verbose.'
|
21
|
+
}
|
22
|
+
option :verbose, {
|
23
|
+
:aliases => :v,
|
24
|
+
:required => false,
|
25
|
+
:type => :boolean,
|
26
|
+
:default => false,
|
27
|
+
:desc => 'Toggle verbose logging'
|
28
|
+
}
|
29
|
+
option :quiet, {
|
30
|
+
:aliases => :q,
|
31
|
+
:required => false,
|
32
|
+
:type => :boolean,
|
33
|
+
:default => false,
|
34
|
+
:desc => 'Surpress all logging'
|
35
|
+
}
|
36
|
+
def build(config)
|
37
|
+
quiet = options[:quiet]
|
38
|
+
unless quiet
|
39
|
+
if options[:logfile].nil? or options[:logfile] == 'STDOUT'
|
40
|
+
Baha::Log.logfile = STDOUT
|
41
|
+
else
|
42
|
+
Baha::Log.logfile = STDOUT
|
43
|
+
end
|
44
|
+
if options[:debug]
|
45
|
+
Baha::Log.level = :debug
|
46
|
+
elsif options[:verbose]
|
47
|
+
Baha::Log.level = :info
|
48
|
+
else
|
49
|
+
Baha::Log.level = :error
|
50
|
+
end
|
51
|
+
end
|
52
|
+
begin
|
53
|
+
builder = Baha::Builder.new(config)
|
54
|
+
builder.build!
|
55
|
+
rescue Exception => e
|
56
|
+
unless quiet
|
57
|
+
Baha::Log.for_name("CLI").fatal("Error encountered while building images")
|
58
|
+
Baha::Log.for_name("CLI").fatal(e)
|
59
|
+
end
|
60
|
+
exit 1
|
61
|
+
ensure
|
62
|
+
Baha::Log.close!
|
63
|
+
end
|
64
|
+
end
|
65
|
+
desc "version", "Print version and exit"
|
66
|
+
def version
|
67
|
+
puts "baha " + Baha::VERSION
|
68
|
+
end
|
69
|
+
end
|