putpaws 0.1.4 → 0.1.6
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 +4 -4
- data/README.md +50 -6
- data/lib/putpaws/provision/config_writer.rb +26 -9
- data/lib/putpaws/provision/preset.rb +2 -0
- data/lib/putpaws/provision/presets/rails/preset.json +35 -0
- data/lib/putpaws/provision/presets/rails/templates/taskdef-app.json.erb +33 -0
- data/lib/putpaws/provision/tasks/provision.rake +4 -2
- data/lib/putpaws/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d6d053460a5c78abad1e20f800e26aae412b0768b47a182380c9e876ebb616f9
|
|
4
|
+
data.tar.gz: bbb6cd4158d334b4029b17cb6141cf52e6e490317f9d438d2af0d43856876728
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bdf0ff9f7a76d786532fe1b4a13991bd0542d2d584c9a1158996ff84f0479913062cc8b5ce9856a27fe3b7d83978e3c6d9e8816753733ac0a43db9e20ea9986b
|
|
7
|
+
data.tar.gz: b3714483e120918f2c777b1dd8f0b010efc4f26268a283a9f1d1a426f0ea0e1b214c033b2fb0e19d2c5b77a498a22f373a994c8ad16620a792993b528e6faa37
|
data/README.md
CHANGED
|
@@ -49,12 +49,40 @@ Presets are searched in this order: project local (`.putpaws/provisioning/preset
|
|
|
49
49
|
user global (directories in `PUTPAWS_PRESETS_PATH`, then `~/.putpaws/presets/`), and the ones bundled in the gem.
|
|
50
50
|
Whichever you pick on `ready` is copied into the project so the project owns its snapshot.
|
|
51
51
|
|
|
52
|
+
Bundled presets (ECS Fargate, `awsvpc`):
|
|
53
|
+
|
|
54
|
+
- `rails` (default) ... one `app` container on port 8080. Assumes the Rails 8 default Dockerfile,
|
|
55
|
+
where [Thruster](https://github.com/basecamp/thruster) fronts Puma and does what an nginx sidecar used to
|
|
56
|
+
(HTTP/2, asset caching / compression, X-Sendfile); TLS terminates at the ALB.
|
|
57
|
+
Thruster listens on port 80 by default, but the Rails Dockerfile runs as a non-root user and
|
|
58
|
+
Fargate does not let non-root processes bind ports below 1024 (unlike local Docker, which sets
|
|
59
|
+
`net.ipv4.ip_unprivileged_port_start=0`), so the preset sets `HTTP_PORT=8080` and
|
|
60
|
+
`container_port: 8080`; point the ALB target group at 8080. The Dockerfile needs no change
|
|
61
|
+
(`EXPOSE 80` is metadata only). Older Rails apps work too by adding the `thruster` gem and
|
|
62
|
+
starting with `bin/thrust bin/rails server`, or by setting `container_port` to the Puma port
|
|
63
|
+
and dropping `HTTP_PORT`.
|
|
64
|
+
- `rails-nginx` ... same `app` task definition plus a `web` one with an nginx sidecar on port 80.
|
|
65
|
+
The sidecar is a stock nginx image with no proxy config, so point `nginx_image` at your own image
|
|
66
|
+
that proxies to `localhost:3000`. Keep this only when you need something Thruster does not do
|
|
67
|
+
(maintenance pages, custom rewrites, proxy-level auth).
|
|
68
|
+
|
|
69
|
+
Need another task definition (Ex: a batch worker)? Add an entry to `task_definitions` of the
|
|
70
|
+
copied preset with its own template; `up` creates it and writes an `application.json` entry for it.
|
|
71
|
+
|
|
52
72
|
Security groups are either specified (one or more existing ones; putpaws never touches their rules)
|
|
53
73
|
or a new one is created for the service when left empty on `ready`.
|
|
54
74
|
|
|
55
75
|
When the service step completes, the new service is reflected into
|
|
56
76
|
`.putpaws/application.json` and `.putpaws/infra.json` (diff is shown and confirmed),
|
|
57
77
|
so `ecs:attach`, `ecs:shell`, `ecs:run` and `log:*` work immediately.
|
|
78
|
+
One entry is written per task definition of the preset, keyed by the task definition
|
|
79
|
+
family `{service_name}-{suffix}` (Ex: `awesome-api-staging-app` / `awesome-api-staging-web`),
|
|
80
|
+
each pointing at the `infra.target` of the same name. Only the entry of the preset's
|
|
81
|
+
`service_task_definition` carries `service` (for `ecs:deploy` / `ecs:attach`); the others have
|
|
82
|
+
`service: null` and are meant for one-off tasks (`ecs:run` / `ecs:shell` / scheduler),
|
|
83
|
+
so with `rails-nginx` `db:migrate` keeps running on the plain `app` task definition while the
|
|
84
|
+
service runs `web` (nginx + app). `infra.network` is written once as `{service_name}`.
|
|
85
|
+
Existing keys are never deleted; remove stale ones by hand.
|
|
58
86
|
Secrets are handled by reference only: task definitions point to existing
|
|
59
87
|
SSM parameters (Ex: `/{service_name}/RAILS_MASTER_KEY`) and putpaws never touches the values.
|
|
60
88
|
|
|
@@ -64,7 +92,7 @@ so `scheduler:deploy` works any time by just writing `.putpaws/schedule.json`.
|
|
|
64
92
|
The CPU architecture is declared once as `cpu_architecture` (`ARM64` / `X86_64`) in the preset
|
|
65
93
|
defaults (overridable per service via `overrides`), and applied consistently to both
|
|
66
94
|
task definitions (`runtimePlatform`) and CodeBuild (environment type and image).
|
|
67
|
-
The bundled
|
|
95
|
+
The bundled presets default to `ARM64`; projects whose copied preset predates this setting
|
|
68
96
|
fall back to `X86_64` so nothing changes silently. When switching an existing service to ARM,
|
|
69
97
|
run the CI build right after `up` so an ARM image exists before tasks roll
|
|
70
98
|
(`devops.environment_type` / `environment_image` can override the derivation for staged migration).
|
|
@@ -225,19 +253,35 @@ gem 'putpaws'
|
|
|
225
253
|
|
|
226
254
|
`.putpaws/application.json`
|
|
227
255
|
|
|
256
|
+
Keys are free-form names you pass to the CLI. The ones written by `putpaws up` follow
|
|
257
|
+
`{service_name}-{suffix}`: `-app` for one-off tasks (`service: null`), `-web` for the
|
|
258
|
+
long-running service.
|
|
259
|
+
|
|
228
260
|
```
|
|
229
261
|
{
|
|
230
|
-
"awesome-api-staging": {
|
|
262
|
+
"awesome-api-staging-app": {
|
|
231
263
|
"region": "ap-northeast-1",
|
|
232
264
|
"cluster": "cluster-staging",
|
|
233
265
|
"service": null,
|
|
234
|
-
"task_name_prefix": "awesome-api",
|
|
235
|
-
"log_group_prefix": "/ecs/awesome
|
|
266
|
+
"task_name_prefix": "awesome-api-staging-app",
|
|
267
|
+
"log_group_prefix": "/ecs/awesome-api-staging",
|
|
268
|
+
"log_region": null,
|
|
269
|
+
"build_log_group_prefix": "/aws/codebuild/awesome-api-staging",
|
|
270
|
+
"build_project_name_prefix": "awesome-api-staging",
|
|
271
|
+
"network": "awesome-api-staging",
|
|
272
|
+
"target": "awesome-api-staging-app"
|
|
273
|
+
},
|
|
274
|
+
"awesome-api-staging-web": {
|
|
275
|
+
"region": "ap-northeast-1",
|
|
276
|
+
"cluster": "cluster-staging",
|
|
277
|
+
"service": "awesome-api-staging",
|
|
278
|
+
"task_name_prefix": "awesome-api-staging-web",
|
|
279
|
+
"log_group_prefix": "/ecs/awesome-api-staging",
|
|
236
280
|
"log_region": null,
|
|
237
281
|
"build_log_group_prefix": "/aws/codebuild/awesome-api-staging",
|
|
238
282
|
"build_project_name_prefix": "awesome-api-staging",
|
|
239
|
-
"network": "awesome-
|
|
240
|
-
"target": "awesome-staging"
|
|
283
|
+
"network": "awesome-api-staging",
|
|
284
|
+
"target": "awesome-api-staging-web"
|
|
241
285
|
},
|
|
242
286
|
"awesome-api-production": {
|
|
243
287
|
"region": "ap-northeast-1",
|
|
@@ -8,6 +8,15 @@ module Putpaws
|
|
|
8
8
|
# Reflects provisioned resources into .putpaws/application.json and
|
|
9
9
|
# .putpaws/infra.json. Only the keys of the target service are touched.
|
|
10
10
|
# Shows a diff and asks for confirmation before writing.
|
|
11
|
+
#
|
|
12
|
+
# One application entry and one infra.target entry are written per task
|
|
13
|
+
# definition of the preset, keyed by the task definition family
|
|
14
|
+
# (`<service_name>-<suffix>`). The entry whose suffix is the preset's
|
|
15
|
+
# `service_task_definition` carries `service` so that ecs:deploy /
|
|
16
|
+
# ecs:attach address the long-running service; the others are for
|
|
17
|
+
# one-off tasks (ecs:run / ecs:shell / scheduler) and have `service: null`.
|
|
18
|
+
# infra.network is written once per service as it does not depend on the
|
|
19
|
+
# task definition.
|
|
11
20
|
class ConfigWriter
|
|
12
21
|
attr_reader :config, :state, :prompt, :io
|
|
13
22
|
def initialize(config:, state:, prompt:, io: $stdout)
|
|
@@ -17,17 +26,18 @@ module Putpaws
|
|
|
17
26
|
@io = io
|
|
18
27
|
end
|
|
19
28
|
|
|
20
|
-
def application_entry
|
|
29
|
+
def application_entry(entry)
|
|
30
|
+
family = config.task_definition_family(entry[:suffix])
|
|
21
31
|
{
|
|
22
32
|
region: config.region,
|
|
23
33
|
cluster: config.cluster_name,
|
|
24
|
-
service: config.service_name,
|
|
25
|
-
task_name_prefix:
|
|
34
|
+
service: service_entry?(entry) ? config.service_name : nil,
|
|
35
|
+
task_name_prefix: family,
|
|
26
36
|
log_group_prefix: config.log_group,
|
|
27
37
|
build_log_group_prefix: config.build_log_group,
|
|
28
38
|
build_project_name_prefix: config.build_project_name,
|
|
29
39
|
network: config.service_name,
|
|
30
|
-
target:
|
|
40
|
+
target: family,
|
|
31
41
|
}
|
|
32
42
|
end
|
|
33
43
|
|
|
@@ -39,25 +49,32 @@ module Putpaws
|
|
|
39
49
|
}
|
|
40
50
|
end
|
|
41
51
|
|
|
42
|
-
def target_entry
|
|
52
|
+
def target_entry(entry)
|
|
43
53
|
{
|
|
44
54
|
# Used by EventBridge Scheduler (scheduler:deploy).
|
|
45
55
|
scheduler_role: config.roles[:scheduler_role_arn],
|
|
46
56
|
cluster: state.resources[:cluster_arn],
|
|
47
57
|
# Revision-less on purpose: always run the latest ACTIVE revision.
|
|
48
|
-
task_definition: config.
|
|
49
|
-
container_name:
|
|
58
|
+
task_definition: config.task_definition_family(entry[:suffix]),
|
|
59
|
+
container_name: entry[:container_name] || 'app',
|
|
50
60
|
}
|
|
51
61
|
end
|
|
52
62
|
|
|
53
63
|
def apply!
|
|
54
|
-
write_key(path('application.json'), [config.service_name.to_sym], application_entry)
|
|
55
64
|
write_key(path('infra.json'), [:network, config.service_name.to_sym], network_entry)
|
|
56
|
-
|
|
65
|
+
config.preset.task_definitions.each do |entry|
|
|
66
|
+
key = config.task_definition_family(entry[:suffix]).to_sym
|
|
67
|
+
write_key(path('application.json'), [key], application_entry(entry))
|
|
68
|
+
write_key(path('infra.json'), [:target, key], target_entry(entry))
|
|
69
|
+
end
|
|
57
70
|
end
|
|
58
71
|
|
|
59
72
|
private
|
|
60
73
|
|
|
74
|
+
def service_entry?(entry)
|
|
75
|
+
entry[:suffix] == config.preset.service_task_definition
|
|
76
|
+
end
|
|
77
|
+
|
|
61
78
|
def path(basename)
|
|
62
79
|
Pathname.new(config.path_prefix).join(basename)
|
|
63
80
|
end
|
|
@@ -6,6 +6,8 @@ module Putpaws
|
|
|
6
6
|
module Provision
|
|
7
7
|
class Preset
|
|
8
8
|
BUILTIN_DIR = File.expand_path('presets', __dir__)
|
|
9
|
+
# Preselected on `ready`: Rails 8 with Thruster, app container only.
|
|
10
|
+
DEFAULT = 'rails'
|
|
9
11
|
|
|
10
12
|
def self.local_dir(path_prefix: '.putpaws')
|
|
11
13
|
Pathname.new(path_prefix).join('provisioning', 'presets')
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"defaults": {
|
|
3
|
+
"cpu_architecture": "ARM64",
|
|
4
|
+
"cpu": "256",
|
|
5
|
+
"memory": "512",
|
|
6
|
+
"desired_count": 1,
|
|
7
|
+
"container_port": 8080,
|
|
8
|
+
"log_retention_days": 30,
|
|
9
|
+
"image_tag": "latest",
|
|
10
|
+
"assign_public_ip": "DISABLED",
|
|
11
|
+
"env": {
|
|
12
|
+
"RAILS_ENV": "production",
|
|
13
|
+
"RACK_ENV": "production",
|
|
14
|
+
"RAILS_LOG_TO_STDOUT": "1",
|
|
15
|
+
"HTTP_PORT": "8080"
|
|
16
|
+
},
|
|
17
|
+
"secrets": {
|
|
18
|
+
"RAILS_MASTER_KEY": "{ssm_parameter_prefix}/RAILS_MASTER_KEY"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"task_definitions": [
|
|
22
|
+
{ "suffix": "app", "template": "taskdef-app.json.erb", "container_name": "app" }
|
|
23
|
+
],
|
|
24
|
+
"service_task_definition": "app",
|
|
25
|
+
"devops_defaults": {
|
|
26
|
+
"source_type": "GITHUB",
|
|
27
|
+
"environment_images": {
|
|
28
|
+
"ARM64": "aws/codebuild/amazonlinux-aarch64-standard:3.0",
|
|
29
|
+
"X86_64": "aws/codebuild/standard:7.0"
|
|
30
|
+
},
|
|
31
|
+
"compute_type": "BUILD_GENERAL1_SMALL",
|
|
32
|
+
"privileged_mode": true,
|
|
33
|
+
"buildspec": "buildspec.yml"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"family": "<%= service_name %>-app",
|
|
3
|
+
"requiresCompatibilities": ["FARGATE"],
|
|
4
|
+
"networkMode": "awsvpc",
|
|
5
|
+
"runtimePlatform": {
|
|
6
|
+
"cpuArchitecture": "<%= cpu_architecture %>",
|
|
7
|
+
"operatingSystemFamily": "LINUX"
|
|
8
|
+
},
|
|
9
|
+
"cpu": "<%= cpu %>",
|
|
10
|
+
"memory": "<%= memory %>",
|
|
11
|
+
"executionRoleArn": "<%= execution_role_arn %>",
|
|
12
|
+
"taskRoleArn": "<%= task_role_arn %>",
|
|
13
|
+
"containerDefinitions": [
|
|
14
|
+
{
|
|
15
|
+
"name": "app",
|
|
16
|
+
"image": "<%= image %>",
|
|
17
|
+
"essential": true,
|
|
18
|
+
"portMappings": [
|
|
19
|
+
{ "containerPort": <%= container_port %>, "protocol": "tcp" }
|
|
20
|
+
],
|
|
21
|
+
"environment": <%= env_json %>,
|
|
22
|
+
"secrets": <%= secrets_json %>,
|
|
23
|
+
"logConfiguration": {
|
|
24
|
+
"logDriver": "awslogs",
|
|
25
|
+
"options": {
|
|
26
|
+
"awslogs-group": "<%= log_group %>",
|
|
27
|
+
"awslogs-region": "<%= region %>",
|
|
28
|
+
"awslogs-stream-prefix": "app"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
@@ -22,8 +22,10 @@ namespace :provision do
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
region = prompt.ask("Region:", default: 'ap-northeast-1')
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
preset_catalog = Putpaws::Provision::Preset.catalog
|
|
26
|
+
preset_choices = preset_catalog.map{|e| ["#{e[:name]} (#{e[:source]})", e[:name]]}.to_h
|
|
27
|
+
preset_default = (preset_catalog.index{|e| e[:name] == Putpaws::Provision::Preset::DEFAULT} || 0) + 1
|
|
28
|
+
preset_name = prompt.select("Preset:", preset_choices, default: preset_default)
|
|
27
29
|
|
|
28
30
|
puts "--- Basic infra (existing resources; used to generate IAM policies) ---"
|
|
29
31
|
vpc_id = prompt.ask("VPC ID:"){|q| q.required(true)}
|
data/lib/putpaws/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: putpaws
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- metheglin
|
|
@@ -182,6 +182,8 @@ files:
|
|
|
182
182
|
- lib/putpaws/provision/presets/rails-nginx/preset.json
|
|
183
183
|
- lib/putpaws/provision/presets/rails-nginx/templates/taskdef-app.json.erb
|
|
184
184
|
- lib/putpaws/provision/presets/rails-nginx/templates/taskdef-web.json.erb
|
|
185
|
+
- lib/putpaws/provision/presets/rails/preset.json
|
|
186
|
+
- lib/putpaws/provision/presets/rails/templates/taskdef-app.json.erb
|
|
185
187
|
- lib/putpaws/provision/provision_config.rb
|
|
186
188
|
- lib/putpaws/provision/provision_task.rb
|
|
187
189
|
- lib/putpaws/provision/resources/base.rb
|