shiplane 0.1.16 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 847be5563eac5f1b7d49c018a662a77d065d31022a1edf22bfeb347526459ada
4
- data.tar.gz: ca5d1d1635161bd9cf4a5286fb2b42a13886ecd5b65df934f5dec5a560b7902e
3
+ metadata.gz: 50eae2e296a334c2af2f5ea208d46aabccef50b18d689d60756992086e545a36
4
+ data.tar.gz: 01763e335f6cae1046cc3808af25b0deeb657de21e52e3721e8b3d46361cf6d4
5
5
  SHA512:
6
- metadata.gz: 9109eed0795ebb3211b118563c89781f621b2bde7c16c38131c1d0b8f62075f1ed3a55da3a5a23ca584e75b211c237f1de4905b0d5bb0e7a17205e659c3d9b56
7
- data.tar.gz: c07ff2c9e6bf6d68f2f983fa8497c2f7128533e34b986eb765d4aa7ea114eada3df65a20ec91d1e27f55c783ed01ad9c6206fc71225ec8a3d341a6a338ead732
6
+ metadata.gz: ce597515a61d717166c1508e99013b329c40114d9481d0067da045eec1519ee7b39211646cdccd388bae32f2b5c6c1c9dffbf59f29985225e2e7958132758350
7
+ data.tar.gz: 17be9eabc9af8c6f5425802a994f61cee4aa5084f63875ad5f10d4028669598b8b5d344a16151c0c054456b9e91d063aec506f1d6772e115b85fd2a50bf78bcb
data/README.md CHANGED
@@ -164,6 +164,11 @@ Shiplane::SafeBuild.wrap do
164
164
  end
165
165
  ```
166
166
 
167
+ #### Using Build Cache
168
+ Shiplane is designed to always build using the --no-cache flag in order to guaranteee clean, repeatable builds, but if you find yourself troubleshooting or otherwise needing to build multiple times, you might like to use the following flag to speed up the process. Note that this is intended to be a debugging tool. Using it for production building could potentially part of the build process to run in one context and another part to run in another. Such a case might cause both positive and negative results that are difficult to troubleshoot because they are not repeatable. Don't do this, but DO use this responsibly to make your life easier when troubleshooting.
169
+
170
+ `USE_BUILD_CACHE=true bundle exec cap production shiplane`
171
+
167
172
  ## Becoming Involved
168
173
  ### Community Channels
169
174
  You can join our [Discord community](https://discord.gg/drrn2YG) to ask any questions you might have or to get ahold of someone in the community who might be able to help you (I hang out here just about every day of the week and most of the weekend). There is no guarantee of service implied, but we absolutely believe in helping out our fellow developers and will do so as we are able. If you feel you know some stuff about Shiplane, feel free to hang out and please help out as well!
@@ -8,7 +8,7 @@ lock '3.11.0'
8
8
  set :application, 'podcaster'
9
9
  set :repo_url, 'git@github.com:kirillian/podcaster.git'
10
10
 
11
- set :deploy_to, '/var/www/battlecryforfreedom'
11
+ set :deploy_to, '/var/www/my_app_network'
12
12
 
13
13
  # Default value for :log_level is :debug
14
14
  # set :log_level, :debug
@@ -54,8 +54,21 @@ set :sha, `git rev-parse HEAD`.chomp
54
54
  set :shiplane_docker_registry_username, ENV['DOCKERHUB_USERNAME']
55
55
  set :shiplane_docker_registry_password, ENV['DOCKERHUB_PASSWORD']
56
56
 
57
+
58
+ set :shiplane_build_environment_variables, {
59
+ # The following example Fetches RAILS_ENV from your Capistrano environment-specific configuration
60
+ # RAILS_ENV: proc { fetch(:rails_env, 'production') },
61
+ }
62
+
63
+ # The following setting points shiplane to Github's Registry
64
+ # set :shiplane_docker_registry_url, 'ghcr.io'
65
+
66
+ # The following settings assign the username and token/password needed to login to a given registry
67
+ # set :shiplane_docker_registry_username, ENV['SHIPLANE_CONTAINER_REGISTRY_USERNAME']
68
+ # set :shiplane_docker_registry_token, ENV['SHIPLANE_CONTAINER_REGISTRY_TOKEN']
69
+
57
70
  set :shiplane_networks, {
58
- battlecryforfreedom: {
71
+ my_app_network: {
59
72
  connections: [
60
73
  "nginx_reverse_proxy",
61
74
  "nginx-proxy-letsencrypt",
@@ -65,28 +78,28 @@ set :shiplane_networks, {
65
78
 
66
79
  set :shiplane_containers, {
67
80
  app: {
68
- alias: 'battlecryforfreedom-app',
81
+ alias: 'my_app-app',
69
82
  volumes: [],
70
83
  environment: [],
71
84
  expose: 3000,
72
85
  capistrano_role: "docker",
73
- repo: "kirillian2/podcaster",
86
+ repo: "my_docker_repo_account_name/my_docker_repo",
74
87
  command: 'bin/start',
75
- virtual_host: "battlecryforfreedom.com",
76
- letsencrypt_email: "john.epperson@battlecryforfreedom.com",
88
+ virtual_host: "my_app.com",
89
+ letsencrypt_email: "john.epperson@my_app_network.com",
77
90
  networks: [
78
- "battlecryforfreedom"
91
+ "my_app_network"
79
92
  ],
80
93
  },
81
94
  sidekiq: {
82
- alias: 'battlecryforfreedom-sidekiq',
95
+ alias: 'my_app-sidekiq',
83
96
  volumes: [],
84
97
  environment: [],
85
98
  capistrano_role: "docker",
86
- repo: "kirillian2/podcaster",
99
+ repo: "my_docker_repo_account_name/my_docker_repo",
87
100
  command: 'bin/start_sidekiq_workers',
88
101
  networks: [
89
- "battlecryforfreedom"
102
+ "my_app_network"
90
103
  ],
91
104
  },
92
105
  redis: {
@@ -101,22 +114,37 @@ set :shiplane_containers, {
101
114
  repo: "redis",
102
115
  tag: "4.0.9-alpine",
103
116
  networks: [
104
- "battlecryforfreedom"
117
+ "my_app_network"
105
118
  ],
119
+ deploy: {
120
+ # This setting will tell shiplane NOT to restart this container every deploy
121
+ restart: false,
122
+ },
106
123
  },
107
124
  postgres: {
108
125
  alias: 'postgres',
109
126
  volumes: [
110
127
  "/var/lib/postgres/data:/var/lib/postgresql/data",
111
128
  ],
129
+ environment: {
130
+ POSTGRES_PASSWORD: ENV['DATABASE_PASSWORD'],
131
+ POSTGRES_USER: ENV['DATABASE_USERNAME'],
132
+ },
133
+ flags: {
134
+ 'shm-size' => '256MB',
135
+ },
112
136
  expose: 5432,
113
137
  publish: 5432,
114
138
  capistrano_role: "docker",
115
139
  repo: "postgres",
116
140
  tag: "9.6",
117
141
  networks: [
118
- "battlecryforfreedom"
142
+ "my_app_network"
119
143
  ],
144
+ deploy: {
145
+ # This setting will tell shiplane NOT to restart this container every deploy
146
+ restart: false,
147
+ },
120
148
  },
121
149
  }
122
150
 
@@ -6,6 +6,8 @@ COPY . $APP_PATH
6
6
 
7
7
  WORKDIR $APP_PATH
8
8
 
9
+ ARG RAILS_ENV production
10
+ ENV RAILS_ENV $RAILS_ENV
9
11
  ARG GITHUB_TOKEN
10
12
  ENV GITHUB_TOKEN $GITHUB_TOKEN
11
13
  ENV SHIPLANE building
@@ -36,7 +38,8 @@ WORKDIR $APP_PATH
36
38
  RUN bundle config --local path vendor/bundle
37
39
  RUN bundle config --local without development:test:assets
38
40
 
39
- ENV RAILS_ENV production
41
+ ARG RAILS_ENV production
42
+ ENV RAILS_ENV $RAILS_ENV
40
43
  ENV SHIPLANE running
41
44
  ENV RAILS_LOG_TO_STDOUT true
42
45
  ENV RAILS_SERVE_STATIC_FILES true
@@ -6,9 +6,12 @@ project:
6
6
  bootstrap:
7
7
  env_file: .env.production
8
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
9
+ package_name: chefdk_3.13.1-1_amd64.deb
10
+ package_url: https://packages.chef.io/files/stable/chefdk/3.13.1/ubuntu/16.04/chefdk_3.13.1-1_amd64.deb
11
11
  build:
12
+ registry:
13
+ # url: ghcr.io # for Github Container Service. Should work for similar services such as Gitlab
14
+ # url: :dockerhub # for default Dockerhub Service
12
15
  settings_folder: .shiplane
13
16
  environment_file: .env.production
14
17
  compose_filepath: docker-compose.yml
@@ -31,9 +34,9 @@ build:
31
34
  - services.container-name.depends_on
32
35
  deploy:
33
36
  servers:
34
- # put the server domain or ip address here
37
+ # `server-url` is your server domain or ip address here (e.g. `12.345.67.89` or `myapp.com`)
35
38
  server-url:
36
- # Only set this flag if you need docker to run as the sudo user (default Ubuntu AMI on AWS requires this)
39
+ # Only set this flag if you need docker to escalate permissions and run everything as sudo (default Ubuntu AMI on AWS requires this)
37
40
  requires_sudo: false
38
41
  # Put SSH options here
39
42
  # ssh_options:
@@ -19,8 +19,99 @@ module Shiplane
19
19
  @postfix = postfix
20
20
 
21
21
  Dotenv.overload File.join(Dir.pwd, build_config.fetch('environment_file', '.env'))
22
+
23
+ # Add any ENV variable overrides from the capistrano configuration
24
+ environment_variable_overrides = fetch(:shiplane_build_environment_variables, {})
25
+ environment_variable_overrides.each do |key, value|
26
+ if value.is_a? Proc
27
+ ENV[key.to_s] = value.call
28
+ else
29
+ ENV[key.to_s] = value
30
+ end
31
+ end
22
32
  end
23
33
 
34
+ def build!
35
+ unless File.exist?(File.join(project_folder, Shiplane::SHIPLANE_CONFIG_FILENAME))
36
+ Shiplane::CheckoutArtifact.checkout!(sha)
37
+ Shiplane::ConvertComposeFile.convert_output!(project_folder, sha)
38
+ end
39
+
40
+ buildable_artifacts.each do |(artifact_name, attributes)|
41
+ compose_context = docker_config.fetch('services', {}).fetch(artifact_name.to_s, {})
42
+ Shiplane::ConvertDockerfile.convert_output!(project_folder, attributes, compose_context)
43
+
44
+ FileUtils.cd project_folder do
45
+ steps(artifact_name, attributes).select{|step| step.fetch(:condition, true) }.each do |step|
46
+ puts step[:notify_before] if step.has_key? :notify_before
47
+ success = system(step[:command])
48
+ raise StepFailureException.new(step[:command], artifact_name) unless success
49
+ puts step[:notify_after] if step.has_key? :notify_after
50
+ end
51
+ end
52
+ end
53
+ rescue StepFailureException => e
54
+ puts e.message
55
+ raise if ENV['RAISE_EXCEPTIONS_ON_FAILED_BUILD']
56
+ end
57
+
58
+ def steps(artifact_name, attributes)
59
+ [
60
+ { command: build_command(artifact_name), notify_before: "Building Artifact: #{artifact_name}...", notify_after: "Docker Compose Built", stop_on_failure: true },
61
+ { command: tag_command(artifact_name, attributes, sha), notify_before: "Tagging Build [#{sha}]...", stop_on_failure: true },
62
+ { command: tag_command(artifact_name, attributes, "#{postfix}-#{sha}"), notify_before: "Tagging Build [#{postfix}-#{sha}]...", stop_on_failure: true, condition: !!postfix },
63
+ { command: tag_command(artifact_name, attributes, "#{postfix}-latest"), notify_before: "Tagging Build [#{postfix}-latest]...", stop_on_failure: true, condition: !!postfix && tag_latest },
64
+ { command: tag_command(artifact_name, attributes), notify_before: "Tagging Build [latest]...", stop_on_failure: true, condition: tag_latest },
65
+ { command: token_login_command , notify_before: "Logging into Container Registry...", stop_on_failure: true },
66
+ { command: push_command(attributes, "#{sha}"), notify_before: "Pushing Image", notify_after: "Completed Artifact: #{artifact_name}...", stop_on_failure: true },
67
+ { command: push_command(attributes, "#{postfix}-#{sha}"), notify_before: "Pushing #{postfix} Image", notify_after: "Completed Artifact: #{artifact_name}...", stop_on_failure: true, condition: !!postfix },
68
+ { command: push_command(attributes, "#{postfix}-latest"), notify_before: "Pushing Latest #{postfix} Image", notify_after: "Completed Latest Artifact: #{artifact_name}...", stop_on_failure: true, condition: !!postfix && tag_latest },
69
+ { command: push_command(attributes, "latest"), notify_before: "Pushing Latest Image", notify_after: "Completed Latest Artifact: #{artifact_name}...", stop_on_failure: true, condition: tag_latest },
70
+ ]
71
+ end
72
+
73
+ # Commands
74
+ def build_command(artifact_name)
75
+ [
76
+ 'docker-compose',
77
+ 'build',
78
+ build_cache_option,
79
+ artifact_name,
80
+ ].compact.join(' ')
81
+ end
82
+
83
+ def token_login_command
84
+ @token_login_command ||= [
85
+ 'echo',
86
+ "\"#{login_token}\"",
87
+ '|',
88
+ 'docker',
89
+ 'login',
90
+ registry_url,
91
+ '--username',
92
+ login_username,
93
+ '--password-stdin',
94
+ ].compact.join(' ')
95
+ end
96
+
97
+ def tag_command(artifact_name, attributes, tag='latest')
98
+ [
99
+ 'docker',
100
+ 'tag',
101
+ build_output_image_name(artifact_name),
102
+ "#{repo_name(attributes)}:#{tag}",
103
+ ].compact.join(' ')
104
+ end
105
+
106
+ def push_command(attributes, tag='latest')
107
+ [
108
+ 'docker',
109
+ 'push',
110
+ "#{repo_name(attributes)}:#{tag}",
111
+ ].compact.join(' ')
112
+ end
113
+
114
+ # Properties
24
115
  def appname
25
116
  @appname ||= project_config['appname']
26
117
  end
@@ -45,44 +136,57 @@ module Shiplane
45
136
  build_config.fetch('artifacts', {})
46
137
  end
47
138
 
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
139
+ def default_registry_configuration
140
+ {
141
+ 'url' => :dockerhub,
142
+ 'auth_method' => 'token',
143
+ }
144
+ end
53
145
 
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)
146
+ def dockerhub?
147
+ registry_configuration['url'] == :dockerhub
148
+ end
57
149
 
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']
150
+ def token_auth?
151
+ registry_configuration['auth_method'] == 'token'
70
152
  end
71
153
 
72
- def steps(artifact_name, attributes)
154
+ def registry_configuration
155
+ @registry_configuration ||= default_registry_configuration.merge(build_config.fetch('registry', {}))
156
+ end
157
+
158
+ def registry_url
159
+ @registry_url ||= dockerhub? ? nil : registry_configuration['url']
160
+ end
161
+
162
+ def repo_name(attributes)
73
163
  [
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
- ]
164
+ registry_url,
165
+ attributes['repo'],
166
+ ].compact.join('/')
167
+ end
168
+
169
+ def login_token
170
+ return ENV['DOCKERHUB_PASSWORD'] if dockerhub? && token_auth?
171
+
172
+ ENV['SHIPLANE_CONTAINER_REGISTRY_TOKEN']
173
+ end
174
+
175
+ def login_username
176
+ return ENV['DOCKERHUB_USERNAME'] if dockerhub? && token_auth?
177
+
178
+ ENV['SHIPLANE_CONTAINER_REGISTRY_USERNAME']
179
+ end
180
+
181
+ def build_output_image_name(artifact_name)
182
+ @build_output_image_name ||= "#{appname}-#{sha}_#{artifact_name}:latest"
183
+ end
184
+
185
+ def build_cache_option
186
+ ENV['USE_BUILD_CACHE'] == 'true' ? nil : "--no-cache"
84
187
  end
85
188
 
189
+ # API Helper Methods
86
190
  def self.build!(sha, postfix = nil)
87
191
  new(sha, postfix: postfix).build!
88
192
  end
@@ -32,10 +32,6 @@ module Shiplane
32
32
 
33
33
  def converted_output
34
34
  @converted_output ||= converted_compose_hash.dup.tap do |hash|
35
- build_config.fetch('artifacts', {}).each do |(appname, config)|
36
- hash.deep_merge!({ 'services' => { appname => { 'image' => "#{config['repo']}:#{sha}" } } })
37
- end
38
-
39
35
  hash.traverse! do |key, value|
40
36
  if (key == 'env_file' && value == '.env.development')
41
37
  [key, '.env.production']
@@ -64,7 +64,7 @@ module Shiplane
64
64
  end
65
65
 
66
66
  def network_connect_commands(role)
67
- @network_commands ||= networks.map do |network|
67
+ @network_commands ||= networks[1..-1].map do |network|
68
68
  [
69
69
  docker_command(role),
70
70
  "network connect",
@@ -84,6 +84,8 @@ module Shiplane
84
84
  published_ports.map{|port| "-p #{port}" },
85
85
  exposed_ports.map{|port| "--expose #{port}" },
86
86
  "--name #{unique_container_name}",
87
+ "--network=#{networks.first}",
88
+ "--network-alias=#{network_alias}",
87
89
  virtual_host ? "-e VIRTUAL_HOST=#{virtual_host}" : nil,
88
90
  letsencrypt_host ? "-e LETSENCRYPT_HOST=#{letsencrypt_host}" : nil,
89
91
  letsencrypt_email ? "-e LETSENCRYPT_EMAIL=#{letsencrypt_email}" : nil,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Shiplane
4
- VERSION = "0.1.16"
4
+ VERSION = "0.2.4"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shiplane
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.16
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Epperson
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-26 00:00:00.000000000 Z
11
+ date: 2021-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: shiplane_bootstrappers_chef
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.1.16
19
+ version: 0.2.4
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.1.16
26
+ version: 0.2.4
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: shiplane_deployers_capistrano_docker
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 0.1.16
33
+ version: 0.2.4
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 0.1.16
40
+ version: 0.2.4
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: dotenv
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -156,7 +156,7 @@ homepage: https://github.com/kirillian/shiplane
156
156
  licenses:
157
157
  - MIT
158
158
  metadata: {}
159
- post_install_message:
159
+ post_install_message:
160
160
  rdoc_options: []
161
161
  require_paths:
162
162
  - lib
@@ -172,7 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
172
172
  version: '0'
173
173
  requirements: []
174
174
  rubygems_version: 3.0.3
175
- signing_key:
175
+ signing_key:
176
176
  specification_version: 4
177
177
  summary: A toolbox for converting developer docker-compose files into production-ready
178
178
  images.