shiplane 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +73 -0
- data/lib/capistrano/shiplane/version.rb +5 -0
- data/lib/capistrano/shiplane.rb +6 -0
- data/lib/capistrano/tasks/capistrano_stubs.rake +122 -0
- data/lib/capistrano/tasks/shiplane.rake +16 -0
- data/lib/generators/shiplane/install/templates/Capfile.erb +13 -0
- data/lib/generators/shiplane/install/templates/deploy.rb.erb +132 -0
- data/lib/generators/shiplane/install/templates/production.rb.erb +61 -0
- data/lib/generators/shiplane/install/templates/production_dockerfile_stages.erb +44 -0
- data/lib/generators/shiplane/install/templates/shiplane.yml.erb +44 -0
- data/lib/shiplane/build.rb +101 -0
- data/lib/shiplane/checkout_artifact.rb +121 -0
- data/lib/shiplane/compose_hash.rb +38 -0
- data/lib/shiplane/configuration.rb +37 -0
- data/lib/shiplane/convert_compose_file.rb +59 -0
- data/lib/shiplane/convert_dockerfile.rb +60 -0
- data/lib/shiplane/deploy/configuration.rb +17 -0
- data/lib/shiplane/deploy/container_configuration.rb +93 -0
- data/lib/shiplane/deploy/network_configuration.rb +40 -0
- data/lib/shiplane/extensions.rb +49 -0
- data/lib/shiplane/host.rb +96 -0
- data/lib/shiplane/railtie.rb +5 -0
- data/lib/shiplane/tasks/install.rake +120 -0
- data/lib/shiplane/version.rb +5 -0
- data/lib/shiplane.rb +11 -0
- metadata +159 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f140db779603d5107c232dd5dca0665c251b39df409c3590498c4485b6df9f1d
|
4
|
+
data.tar.gz: aac47c05deecae0cfbbfbbb1888c664d305ec62434165ee89a3fb68bc6a85881
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 37359831f595b65b12f55756668023e46574626267fb16a71b459404772424f67605a4e614c570a304746d703b9f94b628d64fde64015ff6e3353a3f5469067d
|
7
|
+
data.tar.gz: eae6e737e636a325cad67d06da705cab114dbb7e4468fb7b107e3f03186c91c80748bdcf6831eac39b54b8c04e8033b0602376e698f1b255621ca5a919e3f41a
|
data/README.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# Shiplane
|
2
|
+
Convert your development docker-compose yaml files into production-ready docker deployments
|
3
|
+
|
4
|
+
## The Mission
|
5
|
+
### Empower Developers
|
6
|
+
Shiplane is about empowering developers to get more done, in less time, with less effort. It is intended to amplify a developer's skills and efforts for little cost. It shouldn't take hours and days to setup a working Shiplane environment. It should take minutes to get a working, sane, and relatively secure solution out of the box. Once working, everything should be tweakable as needed.
|
7
|
+
|
8
|
+
### Platform Agnostic
|
9
|
+
Shiplane doesn't care what language you use, what orchestration tool you use, or even what kind of OS you are deploying to or from. Shiplane is merely a well-traveled, sane, and easy to use path through the Docker ecosystem that gets you from having nothing to having a working system.
|
10
|
+
|
11
|
+
## What does Shiplane do for me?
|
12
|
+
### Environment Consistency
|
13
|
+
Your development compose environment already defines all your application's dependencies, so why should you need to recreate your entire environment just to deploy to production? It not only duplicates work, but increases the likelihood of differences between environments that developers are always attempting to mitigate. Shiplane helps you minimize any differences so that the transition from your local, development Docker environment is just another push of code to your CI.
|
14
|
+
|
15
|
+
### Taming the Wild West
|
16
|
+
The sheer number of Docker tools out there is staggering. While they all solve some problem, it can be difficult to decide WHICH tools you want to chain together to make your toolset as a developer new to the Docker ecosystem. Maybe you're not as big as Google and you don't need Kubernetes right now or maybe you just picked up Docker last week, but see it's potential and you're seeking the quickest path to a pipeline right now despite not understanding everything just yet. Shiplane is designed to help you move from having nothing to having a complete Docker ecosystem in a matter of minutes - not hours, days, or weeks.
|
17
|
+
|
18
|
+
### Appropriate division of responsibilities
|
19
|
+
Docker places a lot of power in the hands of developers to define and manage their development environments and how their code is deployed. This is both good and bad. The good side of things includes developers no longer being subject to the work of other groups in your company to provision and deploy. However, the downsides include things like developers having control over platform security, the keys to the kingdom, and infrastructure. While these aren't necessarily evil, these are typically the domain of an infrastructure team to whom these responsibilities are specifically designated. How can these responsibilities be delegated appropriately without taking away the power that the Docker ecosystem provides developers? There are some existing ways to solve these problems, but they require complex systems to be setup to do so. Shiplane is DESIGNED to make this happen out of the box from day 1. It is designed specifically to allow infrastructure teams to be inserted into the process before developers do any work (infrastructure/security can provide base docker images) and during the CI pipeline (so that infrastructure/security teams can manage keys). This allows you to deploy a docker ecosystem quickly and easily with Shiplane and remain confident that you start off pretty secure and are able to continue using it as your processes evolve.
|
20
|
+
|
21
|
+
### Makes it easy to adapt and scale
|
22
|
+
Shiplane is actually designed to be easy to use early on in the process, scale with you, be easy to switch to new tools (say you want to switch from a pure Docker deployment to using Kubernetes), and yet be easy to get rid of should you decide it is no longer for you.
|
23
|
+
|
24
|
+
### Ok, surely there has to be a catch?
|
25
|
+
#### Not really, no. Ok, one minor catch (that you can help me with by contributing!)
|
26
|
+
While Shiplane is language and platform agnostic and you will be able to deploy that Python project or your Java project, it is written in Ruby at this time and therefore requires your machine to have Ruby installed. The instructions for doing so are included below. That's it. That's the only caveat. And, if you are so inclined, I would LOVE to accept PRs to help me create a Shiplane binary or otherwise remove this dependency entirely. There is an issue open [here](https://github.com/kirillian/shiplane/issues/11) to discuss this problem and potential fixes for it.
|
27
|
+
|
28
|
+
## Installation
|
29
|
+
### Installing Ruby
|
30
|
+
#### TODO
|
31
|
+
|
32
|
+
### Installing Shiplane
|
33
|
+
#### Installing locally to a project
|
34
|
+
1. Install Bundler if you don't already have it:
|
35
|
+
```sh
|
36
|
+
gem install bundler
|
37
|
+
```
|
38
|
+
|
39
|
+
2. You can install Shiplane by adding (if you already have one, skip this first step) a Gemfile with the following contents:
|
40
|
+
```Gemfile
|
41
|
+
source 'https://rubygems.org'
|
42
|
+
|
43
|
+
ruby '2.6.2'
|
44
|
+
```
|
45
|
+
|
46
|
+
3. Add the following lines to your Gemfile:
|
47
|
+
```
|
48
|
+
gem 'shiplane' require: false
|
49
|
+
gem 'shiplane_bootstrappers_chef', require: false
|
50
|
+
gem 'shiplane_deployers_capistrano_docker', require: false
|
51
|
+
```
|
52
|
+
|
53
|
+
4. Run bundler to install everything:
|
54
|
+
```sh
|
55
|
+
bundle install
|
56
|
+
```
|
57
|
+
|
58
|
+
#### Installing globally
|
59
|
+
```sh
|
60
|
+
gem install shiplane
|
61
|
+
gem install shiplane_bootstrappers_chef
|
62
|
+
gem install shiplane_deployers_capistrano_docker
|
63
|
+
```
|
64
|
+
|
65
|
+
### Adding the shiplane.yml to your project folder
|
66
|
+
You will need to have a shiplane.yml file in your project's folder in order to configure shiplane.
|
67
|
+
You can generate a default version of this file via the following command:
|
68
|
+
```sh
|
69
|
+
rake shiplane:install[<application_name>]
|
70
|
+
```
|
71
|
+
|
72
|
+
### Using Shiplane
|
73
|
+
#### TODO
|
@@ -0,0 +1,122 @@
|
|
1
|
+
namespace :deploy do
|
2
|
+
task :finishing do
|
3
|
+
end
|
4
|
+
|
5
|
+
task :new_release_path do
|
6
|
+
end
|
7
|
+
|
8
|
+
task :check do
|
9
|
+
end
|
10
|
+
|
11
|
+
task :set_current_revision do
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
# deploy
|
17
|
+
# deploy:check
|
18
|
+
# deploy:check:directories
|
19
|
+
# deploy:check:linked_dirs
|
20
|
+
# deploy:check:linked_files
|
21
|
+
# deploy:check:make_linked_dirs
|
22
|
+
# deploy:cleanup
|
23
|
+
# deploy:cleanup_rollback
|
24
|
+
# deploy:finished
|
25
|
+
# deploy:finishing
|
26
|
+
# deploy:finishing_rollback
|
27
|
+
# deploy:log_revision
|
28
|
+
# deploy:published
|
29
|
+
# deploy:publishing
|
30
|
+
# deploy:revert_release
|
31
|
+
# deploy:reverted
|
32
|
+
# deploy:reverting
|
33
|
+
# deploy:rollback
|
34
|
+
# deploy:set_current_revision
|
35
|
+
# deploy:started
|
36
|
+
# deploy:starting
|
37
|
+
# deploy:symlink:linked_dirs
|
38
|
+
# deploy:symlink:linked_files
|
39
|
+
# deploy:symlink:release
|
40
|
+
# deploy:symlink:shared
|
41
|
+
# deploy:updated
|
42
|
+
# deploy:updating
|
43
|
+
# install
|
44
|
+
|
45
|
+
|
46
|
+
# task :print_config_variables do
|
47
|
+
# end
|
48
|
+
|
49
|
+
# task updating: :new_release_path do
|
50
|
+
# end
|
51
|
+
|
52
|
+
# task :reverting do
|
53
|
+
# end
|
54
|
+
|
55
|
+
# task :publishing do
|
56
|
+
# end
|
57
|
+
|
58
|
+
# task :finishing do
|
59
|
+
# end
|
60
|
+
|
61
|
+
# task :finishing_rollback do
|
62
|
+
# end
|
63
|
+
|
64
|
+
# task :finished do
|
65
|
+
# end
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
# namespace :check do
|
70
|
+
# task :directories do
|
71
|
+
# end
|
72
|
+
|
73
|
+
# task :linked_dirs do
|
74
|
+
# end
|
75
|
+
|
76
|
+
# task :make_linked_dirs do
|
77
|
+
# end
|
78
|
+
|
79
|
+
# task :linked_files do
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
|
83
|
+
# namespace :symlink do
|
84
|
+
# task :release do
|
85
|
+
# end
|
86
|
+
|
87
|
+
# task :shared do
|
88
|
+
# end
|
89
|
+
|
90
|
+
# task :linked_dirs do
|
91
|
+
# end
|
92
|
+
|
93
|
+
# task :linked_files do
|
94
|
+
# end
|
95
|
+
# end
|
96
|
+
|
97
|
+
# task :cleanup do
|
98
|
+
# end
|
99
|
+
|
100
|
+
# task :cleanup_rollback do
|
101
|
+
# end
|
102
|
+
|
103
|
+
# task :log_revision do
|
104
|
+
# end
|
105
|
+
|
106
|
+
# task revert_release: :rollback_release_path do
|
107
|
+
# end
|
108
|
+
|
109
|
+
# task :new_release_path do
|
110
|
+
# end
|
111
|
+
|
112
|
+
# task :rollback_release_path do
|
113
|
+
# end
|
114
|
+
|
115
|
+
task :set_current_revision do
|
116
|
+
end
|
117
|
+
|
118
|
+
# task :set_previous_revision do
|
119
|
+
# end
|
120
|
+
|
121
|
+
# task :restart
|
122
|
+
# task :failed
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'shiplane'
|
3
|
+
|
4
|
+
desc "Convert Docker Container Artifacts From Development to Production and Upload to Docker Hub"
|
5
|
+
task :shiplane, [:appname, :sha] => ['shiplane:default']
|
6
|
+
|
7
|
+
namespace :shiplane do
|
8
|
+
task :default do |t, args|
|
9
|
+
sha = `git rev-parse HEAD`.chomp
|
10
|
+
invoke "shiplane:build", sha
|
11
|
+
end
|
12
|
+
|
13
|
+
task :build, :sha do |t, args|
|
14
|
+
Shiplane::Build.build_latest!(args['sha'], fetch(:stage))
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Load DSL and set up stages
|
2
|
+
require 'capistrano/setup'
|
3
|
+
require 'capistrano/framework'
|
4
|
+
|
5
|
+
require 'capistrano/ssh_doctor'
|
6
|
+
require "airbrussh/capistrano"
|
7
|
+
|
8
|
+
<% gems.each do |gem| -%>
|
9
|
+
require 'capistrano/<%= gem %>'
|
10
|
+
<% end -%>
|
11
|
+
|
12
|
+
# Load custom tasks from `lib/capistrano/tasks` if you have any defined
|
13
|
+
Dir.glob('lib/capistrano/tasks/**/*.rake').each { |r| import r }
|
@@ -0,0 +1,132 @@
|
|
1
|
+
Airbrussh.configure do |config|
|
2
|
+
config.command_output = false
|
3
|
+
end
|
4
|
+
|
5
|
+
# config valid only for current version of Capistrano
|
6
|
+
lock '3.11.0'
|
7
|
+
|
8
|
+
set :application, 'podcaster'
|
9
|
+
set :repo_url, 'git@github.com:kirillian/podcaster.git'
|
10
|
+
|
11
|
+
set :deploy_to, '/var/www/battlecryforfreedom'
|
12
|
+
|
13
|
+
# Default value for :log_level is :debug
|
14
|
+
# set :log_level, :debug
|
15
|
+
|
16
|
+
# Default value for :pty is false
|
17
|
+
# set :pty, true
|
18
|
+
|
19
|
+
# Default value for :linked_files is []
|
20
|
+
set :linked_files, %w( config/database.yml config/secrets.yml .env.production CHANGELOG.md config/sidekiq_scheduler.yml )
|
21
|
+
|
22
|
+
# Default value for linked_dirs is []
|
23
|
+
set :linked_dirs, %w( log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system )
|
24
|
+
|
25
|
+
# Default value for default_env is {}
|
26
|
+
# set :default_env, { path: "/opt/ruby/bin:$PATH" }
|
27
|
+
|
28
|
+
# Default value for keep_releases is 5
|
29
|
+
# set :keep_releases, 5
|
30
|
+
|
31
|
+
set :rbenv_type, :system
|
32
|
+
set :rbenv_ruby, File.read('.ruby-version').strip
|
33
|
+
|
34
|
+
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
|
35
|
+
set :rbenv_map_bins, %w{rake gem bundle ruby rails sidekiq sidekiqctl}
|
36
|
+
set :rbenv_roles, :app
|
37
|
+
|
38
|
+
SSHKit.config.umask = "022"
|
39
|
+
|
40
|
+
set :ssh_options, {
|
41
|
+
forward_agent: true
|
42
|
+
}
|
43
|
+
|
44
|
+
set :passenger_restart_with_touch, true
|
45
|
+
|
46
|
+
set :branch, proc { `git rev-list --max-count=1 --abbrev-commit #{ENV["REVISION"] || ENV["BRANCH"] || "master"}`.chomp }.call
|
47
|
+
|
48
|
+
set :rollbar_token, '07b2c99baf9b43b087ce0dc96957b52f'
|
49
|
+
set :rollbar_env, Proc.new { fetch :stage }
|
50
|
+
set :rollbar_role, Proc.new { :app }
|
51
|
+
|
52
|
+
set :sha, `git rev-parse HEAD`.chomp
|
53
|
+
|
54
|
+
set :shiplane_docker_registry_username, ENV['DOCKERHUB_USERNAME']
|
55
|
+
set :shiplane_docker_registry_password, ENV['DOCKERHUB_PASSWORD']
|
56
|
+
|
57
|
+
set :shiplane_networks, {
|
58
|
+
battlecryforfreedom: {
|
59
|
+
connections: [
|
60
|
+
"nginx_reverse_proxy",
|
61
|
+
"nginx-proxy-letsencrypt",
|
62
|
+
],
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
set :shiplane_containers, {
|
67
|
+
app: {
|
68
|
+
alias: 'battlecryforfreedom-app',
|
69
|
+
volumes: [],
|
70
|
+
environment: [],
|
71
|
+
expose: 3000,
|
72
|
+
capistrano_role: "docker",
|
73
|
+
repo: "kirillian2/podcaster",
|
74
|
+
command: 'bin/start',
|
75
|
+
virtual_host: "battlecryforfreedom.com",
|
76
|
+
letsencrypt_email: "john.epperson@battlecryforfreedom.com",
|
77
|
+
networks: [
|
78
|
+
"battlecryforfreedom"
|
79
|
+
],
|
80
|
+
},
|
81
|
+
sidekiq: {
|
82
|
+
alias: 'battlecryforfreedom-sidekiq',
|
83
|
+
volumes: [],
|
84
|
+
environment: [],
|
85
|
+
capistrano_role: "docker",
|
86
|
+
repo: "kirillian2/podcaster",
|
87
|
+
command: 'bin/start_sidekiq_workers',
|
88
|
+
networks: [
|
89
|
+
"battlecryforfreedom"
|
90
|
+
],
|
91
|
+
},
|
92
|
+
redis: {
|
93
|
+
alias: 'redis',
|
94
|
+
volumes: [
|
95
|
+
"/var/lib/redis:/var/lib/redis/data",
|
96
|
+
],
|
97
|
+
environment: [],
|
98
|
+
expose: 6379,
|
99
|
+
publish: 6379,
|
100
|
+
capistrano_role: "docker",
|
101
|
+
repo: "redis",
|
102
|
+
tag: "4.0.9-alpine",
|
103
|
+
networks: [
|
104
|
+
"battlecryforfreedom"
|
105
|
+
],
|
106
|
+
},
|
107
|
+
postgres: {
|
108
|
+
alias: 'postgres',
|
109
|
+
volumes: [
|
110
|
+
"/var/lib/postgres/data:/var/lib/postgresql/data",
|
111
|
+
],
|
112
|
+
expose: 5432,
|
113
|
+
publish: 5432,
|
114
|
+
capistrano_role: "docker",
|
115
|
+
repo: "postgres",
|
116
|
+
tag: "9.6",
|
117
|
+
networks: [
|
118
|
+
"battlecryforfreedom"
|
119
|
+
],
|
120
|
+
},
|
121
|
+
}
|
122
|
+
|
123
|
+
# namespace :deploy do
|
124
|
+
# before :started, :capture_revision
|
125
|
+
# before :started, :upload_changelog
|
126
|
+
|
127
|
+
# # config/deploy.rb
|
128
|
+
# # after 'deploy:symlink:release', 'letsencrypt:register_client'
|
129
|
+
# # after 'letsencrypt:register_client', 'letsencrypt:authorize_domain'
|
130
|
+
# # after 'letsencrypt:authorize_domain', 'letsencrypt:obtain_certificate'
|
131
|
+
# # after 'letsencrypt:obtain_certificate', 'nginx:reload'
|
132
|
+
# end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# server-based syntax
|
2
|
+
# ======================
|
3
|
+
# Defines a single server with a list of roles and multiple properties.
|
4
|
+
# You can define all roles on a single server, or split them:
|
5
|
+
|
6
|
+
# server 'example.com', user: 'deploy', roles: %w{app db web}, my_property: :my_value
|
7
|
+
# server 'example.com', user: 'deploy', roles: %w{app web}, other_property: :other_value
|
8
|
+
# server 'db.example.com', user: 'deploy', roles: %w{db}
|
9
|
+
|
10
|
+
set :rails_env, 'production'
|
11
|
+
|
12
|
+
# role-based syntax
|
13
|
+
# ==================
|
14
|
+
|
15
|
+
# Defines a role with one or multiple servers. The primary server in each
|
16
|
+
# group is considered to be the first unless any hosts have the primary
|
17
|
+
# property set. Specify the username and a domain or IP for the server.
|
18
|
+
# Don't use `:all`, it's a meta role.
|
19
|
+
|
20
|
+
# role :app, %w{deploy@example.com}, my_property: :my_value
|
21
|
+
# role :web, %w{user1@primary.com user2@additional.com}, other_property: :other_value
|
22
|
+
# role :db, %w{deploy@example.com}
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
# Configuration
|
27
|
+
# =============
|
28
|
+
# You can set any configuration variable like in config/deploy.rb
|
29
|
+
# These variables are then only loaded and set in this stage.
|
30
|
+
# For available Capistrano configuration variables see the documentation page.
|
31
|
+
# http://capistranorb.com/documentation/getting-started/configuration/
|
32
|
+
# Feel free to add new variables to customise your setup.
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
# Custom SSH Options
|
37
|
+
# ==================
|
38
|
+
# You may pass any option but keep in mind that net/ssh understands a
|
39
|
+
# limited set of options, consult the Net::SSH documentation.
|
40
|
+
# http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start
|
41
|
+
#
|
42
|
+
# Global options
|
43
|
+
# --------------
|
44
|
+
# set :ssh_options, {
|
45
|
+
# keys: %w(/home/rlisowski/.ssh/id_rsa),
|
46
|
+
# forward_agent: false,
|
47
|
+
# auth_methods: %w(password)
|
48
|
+
# }
|
49
|
+
#
|
50
|
+
# The server-based syntax can be used to override options:
|
51
|
+
# ------------------------------------
|
52
|
+
# server 'example.com',
|
53
|
+
# user: 'user_name',
|
54
|
+
# roles: %w{web app},
|
55
|
+
# ssh_options: {
|
56
|
+
# user: 'user_name', # overrides user setting above
|
57
|
+
# keys: %w(/home/user_name/.ssh/id_rsa),
|
58
|
+
# forward_agent: false,
|
59
|
+
# auth_methods: %w(publickey password)
|
60
|
+
# # password: 'please use keys'
|
61
|
+
# }
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Build Production Intermediate Image
|
2
|
+
FROM base as production-intermediate
|
3
|
+
|
4
|
+
COPY --from=intermediate $APP_PATH $APP_PATH
|
5
|
+
COPY . $APP_PATH
|
6
|
+
|
7
|
+
WORKDIR $APP_PATH
|
8
|
+
|
9
|
+
ARG GITHUB_TOKEN
|
10
|
+
ENV GITHUB_TOKEN $GITHUB_TOKEN
|
11
|
+
ENV SHIPLANE building
|
12
|
+
ENV RAILS_ENV production
|
13
|
+
|
14
|
+
RUN mkdir .git && \
|
15
|
+
touch .git/config
|
16
|
+
|
17
|
+
RUN git config --global url."https://$GITHUB_TOKEN:@github.com/".insteadOf "https://github.com/"
|
18
|
+
RUN git config --global --add url."https://$GITHUB_TOKEN:@github.com/".insteadOf "ssh://git@github.com/"
|
19
|
+
|
20
|
+
RUN bundle install --deployment --jobs=4 --without development test
|
21
|
+
|
22
|
+
RUN yarn install --production
|
23
|
+
|
24
|
+
RUN rm -rf node_modules/n2-styles/test/
|
25
|
+
|
26
|
+
RUN bundle exec rake assets:precompile
|
27
|
+
|
28
|
+
RUN sed -i "s/${GITHUB_TOKEN}//" Gemfile.lock
|
29
|
+
|
30
|
+
|
31
|
+
# Build Production Image
|
32
|
+
FROM base as production
|
33
|
+
|
34
|
+
COPY --from=production-intermediate $APP_PATH $APP_PATH
|
35
|
+
|
36
|
+
WORKDIR $APP_PATH
|
37
|
+
|
38
|
+
RUN bundle config --local path vendor/bundle
|
39
|
+
RUN bundle config --local without development:test:assets
|
40
|
+
|
41
|
+
ENV RAILS_ENV production
|
42
|
+
ENV SHIPLANE running
|
43
|
+
ENV RAILS_LOG_TO_STDOUT true
|
44
|
+
ENV RAILS_SERVE_STATIC_FILES true
|
@@ -0,0 +1,44 @@
|
|
1
|
+
project:
|
2
|
+
appname: <%= app_name %>
|
3
|
+
version_control: git
|
4
|
+
# The origin url on Github
|
5
|
+
# origin: username/repo_title
|
6
|
+
bootstrap:
|
7
|
+
env_file: .env.production
|
8
|
+
chef-bootstrapper:
|
9
|
+
package_name: chefdk_3.6.57-1_amd64.deb
|
10
|
+
package_url: https://packages.chef.io/files/stable/chefdk/3.6.57/ubuntu/18.04/chefdk_3.6.57-1_amd64.deb
|
11
|
+
build:
|
12
|
+
settings_folder: .shiplane
|
13
|
+
environment_file: .env.production
|
14
|
+
compose_filepath: docker-compose.yml
|
15
|
+
dockerfile_filepath: Dockerfile
|
16
|
+
# Define the artifacts that you want built here
|
17
|
+
artifacts:
|
18
|
+
container-name:
|
19
|
+
tag: <%= app_name %>-base:latest
|
20
|
+
repo: kirillian2/<%= app_name %>
|
21
|
+
ports:
|
22
|
+
- "3000:3000"
|
23
|
+
compose:
|
24
|
+
whitelist:
|
25
|
+
- services.container-name
|
26
|
+
blacklist:
|
27
|
+
- services.container-name.tty
|
28
|
+
- services.container-name.stdin_open
|
29
|
+
- services.container-name.volumes
|
30
|
+
- services.container-name.ports
|
31
|
+
- services.container-name.depends_on
|
32
|
+
deploy:
|
33
|
+
servers:
|
34
|
+
# put the server domain or ip address here
|
35
|
+
server-url:
|
36
|
+
# Only set this flag if you need docker to run as the sudo user (default Ubuntu AMI on AWS requires this)
|
37
|
+
requires_sudo: false
|
38
|
+
# Put SSH options here
|
39
|
+
# ssh_options:
|
40
|
+
# user: a_user
|
41
|
+
# keys: "path/to/ssh/keys"
|
42
|
+
# forward_agent: true
|
43
|
+
# auth_methods:
|
44
|
+
# - publickey
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'dotenv'
|
3
|
+
|
4
|
+
require_relative 'checkout_artifact'
|
5
|
+
require_relative 'convert_compose_file'
|
6
|
+
require_relative 'convert_dockerfile'
|
7
|
+
require_relative 'configuration'
|
8
|
+
|
9
|
+
module Shiplane
|
10
|
+
class Build
|
11
|
+
extend Forwardable
|
12
|
+
attr_accessor :sha, :postfix, :tag_latest
|
13
|
+
|
14
|
+
delegate %i(build_config project_config) => :shiplane_config
|
15
|
+
|
16
|
+
def initialize(sha, postfix:, tag_latest: false)
|
17
|
+
@sha = sha
|
18
|
+
@tag_latest = tag_latest
|
19
|
+
@postfix = postfix
|
20
|
+
|
21
|
+
Dotenv.overload File.join(Dir.pwd, build_config.fetch('environment_file', '.env'))
|
22
|
+
end
|
23
|
+
|
24
|
+
def appname
|
25
|
+
@appname ||= project_config['appname']
|
26
|
+
end
|
27
|
+
|
28
|
+
def project_folder_name
|
29
|
+
@project_folder_name ||= "#{appname}-#{sha}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def project_folder
|
33
|
+
@project_folder ||= File.join(Dir.pwd, 'docker_builds', appname, project_folder_name)
|
34
|
+
end
|
35
|
+
|
36
|
+
def shiplane_config
|
37
|
+
@shiplane_config ||= Shiplane::Configuration.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def docker_config
|
41
|
+
@docker_config ||= YAML.load(File.new(File.join(project_folder, 'docker-compose.yml')))
|
42
|
+
end
|
43
|
+
|
44
|
+
def buildable_artifacts
|
45
|
+
build_config.fetch('artifacts', {})
|
46
|
+
end
|
47
|
+
|
48
|
+
def build!
|
49
|
+
unless File.exist?(File.join(project_folder, Shiplane::SHIPLANE_CONFIG_FILENAME))
|
50
|
+
Shiplane::CheckoutArtifact.checkout!(sha)
|
51
|
+
Shiplane::ConvertComposeFile.convert_output!(project_folder, sha)
|
52
|
+
end
|
53
|
+
|
54
|
+
buildable_artifacts.each do |(artifact_name, attributes)|
|
55
|
+
compose_context = docker_config.fetch('services', {}).fetch(artifact_name.to_s, {})
|
56
|
+
Shiplane::ConvertDockerfile.convert_output!(project_folder, attributes, compose_context)
|
57
|
+
|
58
|
+
FileUtils.cd project_folder do
|
59
|
+
steps(artifact_name, attributes).select{|step| step.fetch(:condition, true) }.each do |step|
|
60
|
+
puts step[:notify_before] if step.has_key? :notify_before
|
61
|
+
success = system(step[:command])
|
62
|
+
raise StepFailureException.new(step[:command], artifact_name) unless success
|
63
|
+
puts step[:notify_after] if step.has_key? :notify_after
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
rescue StepFailureException => e
|
68
|
+
puts e.message
|
69
|
+
raise if ENV['RAISE_EXCEPTIONS_ON_FAILED_BUILD']
|
70
|
+
end
|
71
|
+
|
72
|
+
def steps(artifact_name, attributes)
|
73
|
+
[
|
74
|
+
{ command: "docker-compose build --no-cache #{artifact_name}", notify_before: "Building Artifact: #{artifact_name}...", notify_after: "Docker Compose Built", stop_on_failure: true },
|
75
|
+
{ command: "docker tag #{attributes['repo']}:#{sha} #{attributes['repo']}:#{postfix}-#{sha}", notify_before: "Tagging Build...", stop_on_failure: true, condition: !!postfix },
|
76
|
+
{ command: "docker tag #{attributes['repo']}:#{sha} #{attributes['repo']}:#{postfix}-latest", notify_before: "Tagging Build...", stop_on_failure: true, condition: !!postfix && tag_latest },
|
77
|
+
{ command: "docker tag #{attributes['repo']}:#{sha} #{attributes['repo']}:latest", notify_before: "Tagging Latest Build...", stop_on_failure: true, condition: tag_latest },
|
78
|
+
{ command: "echo '#{ENV['DOCKERHUB_PASSWORD']}' | docker login --username #{ENV['DOCKERHUB_USERNAME']} --password-stdin", notify_before: "Logging into DockerHub...", stop_on_failure: true },
|
79
|
+
{ command: "docker push '#{attributes['repo']}:#{sha}'", notify_before: "Pushing Image", notify_after: "Completed Artifact: #{artifact_name}...", stop_on_failure: true },
|
80
|
+
{ command: "docker push '#{attributes['repo']}:#{postfix}-#{sha}'", notify_before: "Pushing #{postfix} Image", notify_after: "Completed Artifact: #{artifact_name}...", stop_on_failure: true, condition: !!postfix },
|
81
|
+
{ command: "docker push '#{attributes['repo']}:#{postfix}-latest'", notify_before: "Pushing Latest #{postfix} Image", notify_after: "Completed Latest Artifact: #{artifact_name}...", stop_on_failure: true, condition: !!postfix && tag_latest },
|
82
|
+
{ command: "docker push '#{attributes['repo']}:latest'", notify_before: "Pushing Latest Image", notify_after: "Completed Latest Artifact: #{artifact_name}...", stop_on_failure: true, condition: tag_latest },
|
83
|
+
]
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.build!(sha, postfix = nil)
|
87
|
+
new(sha, postfix: postfix).build!
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.build_latest!(sha, postfix = nil)
|
91
|
+
new(sha, postfix: postfix, tag_latest: true).build!
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class StepFailureException < RuntimeError
|
97
|
+
def initialize(command, artifact_name)
|
98
|
+
message = "Command [#{command}] failed for artifact: #{artifact_name}" if artifact_name
|
99
|
+
super(message)
|
100
|
+
end
|
101
|
+
end
|