cpl 1.0.1 → 1.0.2
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/CHANGELOG.md +32 -3
- data/Gemfile.lock +2 -2
- data/README.md +44 -109
- data/docs/commands.md +12 -0
- data/docs/migrating.md +262 -0
- data/lib/command/ps_start.rb +1 -3
- data/lib/command/ps_stop.rb +3 -5
- data/lib/command/ps_wait.rb +35 -0
- data/lib/core/controlplane.rb +20 -0
- data/lib/cpl/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97534e7ffeb4c0b6c7db70851d6cbac5f86ca0329a76af9975dc4a164eeb08b3
|
4
|
+
data.tar.gz: 3e8a4e9a60af5859bf157464a164f3b7b430a335a33815d65d9bbc54415d43b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 41f11336b2c8a741693e5acc415225bf64d19b4fd0f2240da6ee3de884a517abdb23a37b1ebe166b5b8fd0ccf4d0ae0b95cb7fb3cce0c8f770bfd7c7bc5c6e3e
|
7
|
+
data.tar.gz: e3367bea0aeca04add5823d7129f0ffa3f276709e967d5fe6e533241c8fbace80dd1811b54cb2ee7fd71ce500d54535e4bbe4aea76a1c58114ecf324a3fee763
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,38 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
|
3
|
+
All notable changes to this project's source code will be documented in this file. Items under `Unreleased` are upcoming features that will be out in the next version.
|
4
4
|
|
5
|
-
|
5
|
+
## Contributors
|
6
6
|
|
7
|
-
|
7
|
+
Please follow the recommendations outlined at [keepachangelog.com](https://keepachangelog.com). Please use the existing headings and styling as a guide, and add a link for the version diff at the bottom of the file. Also, please update the `Unreleased` link to compare it to the latest release version.
|
8
|
+
|
9
|
+
## Versions
|
10
|
+
|
11
|
+
## [Unreleased]
|
12
|
+
|
13
|
+
Changes since the last non-beta release.
|
14
|
+
|
15
|
+
_Please add entries here for your pull requests that are not yet released._
|
16
|
+
|
17
|
+
### Added
|
18
|
+
|
19
|
+
- Added steps to migrate to docs. [PR 57](https://github.com/shakacode/heroku-to-control-plane/pull/57) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
|
20
|
+
- Added `ps:wait` command. [PR 58](https://github.com/shakacode/heroku-to-control-plane/pull/58) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
|
21
|
+
|
22
|
+
## [1.0.1] - 2023-06-28
|
23
|
+
|
24
|
+
### Fixed
|
25
|
+
|
26
|
+
- Fixed `cleanup-stale-apps` command when app does not have image. [PR 55](https://github.com/shakacode/heroku-to-control-plane/pull/55) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
|
27
|
+
|
28
|
+
### Changed
|
29
|
+
|
30
|
+
- Improved docs. [PR 50](https://github.com/shakacode/heroku-to-control-plane/pull/50) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
|
31
|
+
|
32
|
+
## [1.0.0] - 2023-05-29
|
8
33
|
|
9
34
|
- Initial release
|
35
|
+
|
36
|
+
[Unreleased]: https://github.com/shakacode/heroku-to-control-plane/compare/v1.0.1...HEAD
|
37
|
+
[1.0.1]: https://github.com/shakacode/heroku-to-control-plane/compare/v1.0.0...v1.0.1
|
38
|
+
[1.0.0]: https://github.com/shakacode/heroku-to-control-plane/releases/tag/v1.0.0
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cpl (1.0.
|
4
|
+
cpl (1.0.2)
|
5
5
|
debug (~> 1.7.1)
|
6
6
|
dotenv (~> 2.8.1)
|
7
7
|
psych (~> 5.1.0)
|
@@ -25,7 +25,7 @@ GEM
|
|
25
25
|
hashdiff (1.0.1)
|
26
26
|
iniparse (1.5.0)
|
27
27
|
io-console (0.6.0)
|
28
|
-
irb (1.7.
|
28
|
+
irb (1.7.1)
|
29
29
|
reline (>= 0.3.0)
|
30
30
|
json (2.6.3)
|
31
31
|
overcommit (0.60.0)
|
data/README.md
CHANGED
@@ -28,10 +28,8 @@ a **helper CLI** based on templates to save lots of day-to-day typing (and human
|
|
28
28
|
1. [Key Features](#key-features)
|
29
29
|
2. [Concept Mapping](#concept-mapping)
|
30
30
|
3. [Installation](#installation)
|
31
|
-
4. [
|
32
|
-
|
33
|
-
- [Promoting Code Upgrades](#promoting-code-upgrades)
|
34
|
-
5. [Example Project Modifications for Control Plane](#example-project-modifications-for-control-plane)
|
31
|
+
4. [Steps to Migrate](#steps-to-migrate)
|
32
|
+
5. [Config](#config)
|
35
33
|
6. [Environment](#environment)
|
36
34
|
7. [Database](#database)
|
37
35
|
8. [In-memory Databases](#in-memory-databases)
|
@@ -110,104 +108,13 @@ gem install cpl
|
|
110
108
|
**Note:** Do not confuse the `cpl` CLI with the `cpln` CLI. The `cpl` CLI is the Heroku to Control Plane playbook CLI.
|
111
109
|
The `cpln` CLI is the Control Plane CLI.
|
112
110
|
|
113
|
-
##
|
111
|
+
## Steps to Migrate
|
114
112
|
|
115
|
-
|
113
|
+
Click [here](/docs/migrating.md) to see the steps to migrate.
|
116
114
|
|
117
|
-
|
118
|
-
[this `controlplane.yml` file](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/controlplane.yml).
|
119
|
-
- Other files in the `.controlplane/templates/` directory are used by the `cpl setup-app` and `cpl apply-template`
|
120
|
-
commands.
|
115
|
+
## Config
|
121
116
|
|
122
|
-
|
123
|
-
|
124
|
-
For each Git project that you want to deploy to Control Plane, copy project-specific configs to a `.controlplane/`
|
125
|
-
directory at the top of your project. `cpl` will pick those up depending on which project folder tree it runs. Thus,
|
126
|
-
this automates running several projects with different configs without explicitly switching configs.
|
127
|
-
|
128
|
-
Before the initial setup, add the templates for the app to `.controlplane/controlplane.yml`, using the `setup` key, e.g.:
|
129
|
-
|
130
|
-
```yaml
|
131
|
-
my-app:
|
132
|
-
setup:
|
133
|
-
- gvc
|
134
|
-
- postgres
|
135
|
-
- redis
|
136
|
-
- memcached
|
137
|
-
- rails
|
138
|
-
- sidekiq
|
139
|
-
```
|
140
|
-
|
141
|
-
Note how the templates correspond to files in the `.controlplane/templates/` directory.
|
142
|
-
|
143
|
-
Then create a `Dockerfile` for your deployment. See
|
144
|
-
[this example](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/Dockerfile).
|
145
|
-
|
146
|
-
```sh
|
147
|
-
# Provision infrastructure (one-time-only for new apps) using templates.
|
148
|
-
cpl setup-app -a my-app
|
149
|
-
|
150
|
-
# Build and push image with auto-tagging, e.g., "my-app:1_456".
|
151
|
-
cpl build-image -a my-app --commit 456
|
152
|
-
|
153
|
-
# Prepare database.
|
154
|
-
cpl run:detached -a my-app --image latest -- rails db:prepare
|
155
|
-
|
156
|
-
# Deploy latest image.
|
157
|
-
cpl deploy-image -a my-app
|
158
|
-
|
159
|
-
# Open app in browser.
|
160
|
-
cpl open -a my-app
|
161
|
-
```
|
162
|
-
|
163
|
-
### Promoting Code Upgrades
|
164
|
-
|
165
|
-
```sh
|
166
|
-
# Build and push new image with sequential tagging, e.g., "my-app:2".
|
167
|
-
cpl build-image -a my-app
|
168
|
-
|
169
|
-
# Or build and push new image with sequential tagging and commit SHA, e.g., "my-app:2_ABC".
|
170
|
-
cpl build-image -a my-app --commit ABC
|
171
|
-
|
172
|
-
# Run database migrations (or other release tasks) with latest image, while app is still running on previous image.
|
173
|
-
# This is analogous to the release phase.
|
174
|
-
cpl run:detached -a my-app --image latest -- rails db:migrate
|
175
|
-
|
176
|
-
# Deploy latest image.
|
177
|
-
cpl deploy-image -a my-app
|
178
|
-
```
|
179
|
-
|
180
|
-
## Example Project Modifications for Control Plane
|
181
|
-
|
182
|
-
_See this for a complete example._
|
183
|
-
|
184
|
-
To learn how to migrate an app, we recommend following along with
|
185
|
-
[this example project](https://github.com/shakacode/react-webpack-rails-tutorial).
|
186
|
-
|
187
|
-
1. Create the `.controlplane/` directory at the top of your project and copy files from the `templates/` directory of
|
188
|
-
this repository to something as follows:
|
189
|
-
|
190
|
-
```sh
|
191
|
-
app_main_folder/
|
192
|
-
.controlplane/
|
193
|
-
Dockerfile # Your app's Dockerfile, with some Control Plane changes.
|
194
|
-
controlplane.yml
|
195
|
-
entrypoint.sh # App-specific - edit as needed.
|
196
|
-
templates/
|
197
|
-
gvc.yml
|
198
|
-
memcached.yml
|
199
|
-
postgres.yml
|
200
|
-
rails.yml
|
201
|
-
redis.yml
|
202
|
-
sidekiq.yml
|
203
|
-
```
|
204
|
-
|
205
|
-
The example
|
206
|
-
[`.controlplane/` directory](https://github.com/shakacode/react-webpack-rails-tutorial/tree/master/.controlplane)
|
207
|
-
already contains these files.
|
208
|
-
|
209
|
-
2. Edit your `controlplane.yml` file as needed. For example, see
|
210
|
-
[this `controlplane.yml` file](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/controlplane.yml).
|
117
|
+
Here's a complete example of all supported config keys explained:
|
211
118
|
|
212
119
|
```yaml
|
213
120
|
# Keys beginning with "cpln_" correspond to your settings in Control Plane.
|
@@ -221,6 +128,16 @@ aliases:
|
|
221
128
|
# Example apps use only one location. Control Plane offers the ability to use multiple locations.
|
222
129
|
default_location: aws-us-east-2
|
223
130
|
|
131
|
+
# Allows running the command `cpl setup-app`
|
132
|
+
# instead of `cpl apply-template gvc redis postgres memcached rails sidekiq`.
|
133
|
+
setup:
|
134
|
+
- gvc
|
135
|
+
- redis
|
136
|
+
- postgres
|
137
|
+
- memcached
|
138
|
+
- rails
|
139
|
+
- sidekiq
|
140
|
+
|
224
141
|
# Configure the workload name used as a template for one-off scripts, like a Heroku one-off dyno.
|
225
142
|
one_off_workload: rails
|
226
143
|
|
@@ -235,40 +152,58 @@ aliases:
|
|
235
152
|
- postgres
|
236
153
|
- memcached
|
237
154
|
|
238
|
-
# Configure the workload name used when maintenance mode is on (defaults to "maintenance")
|
155
|
+
# Configure the workload name used when maintenance mode is on (defaults to "maintenance").
|
239
156
|
maintenance_workload: maintenance
|
240
157
|
|
158
|
+
# Fixes the remote terminal size to match the local terminal size
|
159
|
+
# when running the commands `cpl run` or `cpl run:detached`.
|
160
|
+
fix_terminal_size: true
|
161
|
+
|
162
|
+
# Apps with a deployed image created before this amount of days will be listed for deletion
|
163
|
+
# when running the command `cpl cleanup-stale-apps`.
|
164
|
+
stale_app_image_deployed_days: 5
|
165
|
+
|
166
|
+
# Images created before this amount of days will be listed for deletion
|
167
|
+
# when running the command `cpl cleanup-old-images`.
|
168
|
+
old_image_retention_days: 5
|
169
|
+
|
170
|
+
# Run workloads created before this amount of days will be listed for deletion
|
171
|
+
# when running the command `cpl run:cleanup`.
|
172
|
+
stale_run_workload_created_days: 2
|
173
|
+
|
241
174
|
apps:
|
242
175
|
my-app-staging:
|
243
176
|
# Use the values from the common section above.
|
244
177
|
<<: *common
|
178
|
+
|
245
179
|
my-app-review:
|
246
180
|
<<: *common
|
181
|
+
|
247
182
|
# If `match_if_app_name_starts_with` is `true`, then use this config for app names starting with this name,
|
248
183
|
# e.g., "my-app-review-pr123", "my-app-review-anything-goes", etc.
|
249
184
|
match_if_app_name_starts_with: true
|
185
|
+
|
250
186
|
my-app-production:
|
251
187
|
<<: *common
|
188
|
+
|
252
189
|
# Use a different organization for production.
|
253
190
|
cpln_org: my-org-production
|
191
|
+
|
254
192
|
# Allows running the command `cpl promote-app-from-upstream -a my-app-production`
|
255
193
|
# to promote the staging app to production.
|
256
194
|
upstream: my-app-staging
|
195
|
+
|
196
|
+
# Used by the command `cpl promote-app-from-upstream` to run a release script before deploying.
|
197
|
+
# This is relative to the `.controlplane/` directory.
|
198
|
+
release_script: release_script
|
199
|
+
|
257
200
|
my-app-other:
|
258
201
|
<<: *common
|
202
|
+
|
259
203
|
# You can specify a different `Dockerfile` relative to the `.controlplane/` directory (defaults to "Dockerfile").
|
260
204
|
dockerfile: ../some_other/Dockerfile
|
261
205
|
```
|
262
206
|
|
263
|
-
3. We recommend that you try out the commands listed in
|
264
|
-
[the example](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/readme.md).
|
265
|
-
These steps will guide you to the following:
|
266
|
-
|
267
|
-
1. Provision the GVC and workloads.
|
268
|
-
2. Build the Docker image.
|
269
|
-
3. Run Rails migrations, like in the Heroku release phase.
|
270
|
-
4. Promote the latest Docker image.
|
271
|
-
|
272
207
|
## Environment
|
273
208
|
|
274
209
|
There are two main places where we can set up environment variables in Control Plane:
|
data/docs/commands.md
CHANGED
@@ -285,6 +285,18 @@ cpl ps:stop -a $APP_NAME
|
|
285
285
|
cpl ps:stop -a $APP_NAME -w $WORKLOAD_NAME
|
286
286
|
```
|
287
287
|
|
288
|
+
### `ps:wait`
|
289
|
+
|
290
|
+
- Waits for workloads in app to be ready after re-deployment
|
291
|
+
|
292
|
+
```sh
|
293
|
+
# Waits for all workloads in app.
|
294
|
+
cpl ps:wait -a $APP_NAME
|
295
|
+
|
296
|
+
# Waits for a specific workload in app.
|
297
|
+
cpl ps:swait -a $APP_NAME -w $WORKLOAD_NAME
|
298
|
+
```
|
299
|
+
|
288
300
|
### `run`
|
289
301
|
|
290
302
|
- Runs one-off **_interactive_** replicas (analog of `heroku run`)
|
data/docs/migrating.md
ADDED
@@ -0,0 +1,262 @@
|
|
1
|
+
# Steps to Migrate from Heroku to Control Plane
|
2
|
+
|
3
|
+
We recommend following along with
|
4
|
+
[this example project](https://github.com/shakacode/react-webpack-rails-tutorial).
|
5
|
+
|
6
|
+
1. [Clone the Staging Environment](#clone-the-staging-environment)
|
7
|
+
- [Review Special Gems](#review-special-gems)
|
8
|
+
- [Create a Minimum Bootable Config](#create-a-minimum-bootable-config)
|
9
|
+
2. [Create the Review App Process](#create-the-review-app-process)
|
10
|
+
- [Database for Review Apps](#database-for-review-apps)
|
11
|
+
- [Redis and Memcached for Review Apps](#redis-and-memcached-for-review-apps)
|
12
|
+
3. [Deploy to Production](#deploy-to-production)
|
13
|
+
|
14
|
+
## Clone the Staging Environment
|
15
|
+
|
16
|
+
By cloning the staging environment on Heroku, you can speed up the initial provisioning of the app on Control Plane
|
17
|
+
without compromising your current environment.
|
18
|
+
|
19
|
+
Consider migrating just the web dyno first, and get other types of dynos working afterward. You can also move the
|
20
|
+
add-ons to Control Plane later once the app works as expected.
|
21
|
+
|
22
|
+
First, create a new Heroku app with all the add-ons, copying the data from the current staging app.
|
23
|
+
|
24
|
+
Then, copy project-specific configs to a `.controlplane/` directory at the top of your project. `cpl` will pick those up
|
25
|
+
depending on which project folder tree it runs. Thus, this automates running several projects with different configs
|
26
|
+
without explicitly switching configs.
|
27
|
+
|
28
|
+
Edit the `.controlplane/controlplane.yml` file as needed. Note that the `my-app-staging` name used in the examples below
|
29
|
+
is defined in this file. See
|
30
|
+
[this example](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/controlplane.yml).
|
31
|
+
|
32
|
+
Before the initial setup, add the templates for the app to the `.controlplane/controlplane.yml` file, using the `setup`
|
33
|
+
key, e.g.:
|
34
|
+
|
35
|
+
```yaml
|
36
|
+
my-app-staging:
|
37
|
+
<<: *common
|
38
|
+
setup:
|
39
|
+
- gvc
|
40
|
+
- redis
|
41
|
+
- memcached
|
42
|
+
- rails
|
43
|
+
- sidekiq
|
44
|
+
```
|
45
|
+
|
46
|
+
Note how the templates correspond to files in the `.controlplane/templates/` directory. These files will be used by the
|
47
|
+
`cpl setup-app` and `cpl apply-template` commands.
|
48
|
+
|
49
|
+
Ensure that env vars point to the Heroku add-ons in the template for the app (`.controlplane/templates/gvc.yml`). See
|
50
|
+
[this example](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/templates/gvc.yml).
|
51
|
+
|
52
|
+
After that, create a Dockerfile in `.controlplane/Dockerfile` for your deployment. See
|
53
|
+
[this example](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/Dockerfile).
|
54
|
+
|
55
|
+
You should have a folder structure similar to the following:
|
56
|
+
|
57
|
+
```sh
|
58
|
+
app_main_folder/
|
59
|
+
.controlplane/
|
60
|
+
Dockerfile # Your app's Dockerfile, with some Control Plane changes.
|
61
|
+
controlplane.yml
|
62
|
+
entrypoint.sh # App-specific - edit as needed.
|
63
|
+
templates/
|
64
|
+
gvc.yml
|
65
|
+
memcached.yml
|
66
|
+
rails.yml
|
67
|
+
redis.yml
|
68
|
+
sidekiq.yml
|
69
|
+
```
|
70
|
+
|
71
|
+
The example
|
72
|
+
[`.controlplane/` directory](https://github.com/shakacode/react-webpack-rails-tutorial/tree/master/.controlplane)
|
73
|
+
already contains these files.
|
74
|
+
|
75
|
+
Finally, check the app for any Heroku-specific code and update it, such as the `HEROKU_SLUG_COMMIT` env var and other
|
76
|
+
env vars beginning with `HEROKU_`. You should add some logic to check for the Control Plane equivalents - it might be
|
77
|
+
worth adding a `CONTROLPLANE` env var to act as a feature flag and help run different code for Heroku and Control Plane
|
78
|
+
until the migration is complete.
|
79
|
+
|
80
|
+
You might want to [review special gems](#review-special-gems) and
|
81
|
+
[create a minimum bootable config](#create-a-minimum-bootable-config).
|
82
|
+
|
83
|
+
At first, do the deployments from the command line. Then set up CI scripts to trigger the deployment upon merges to
|
84
|
+
master/main.
|
85
|
+
|
86
|
+
Use these commands for the initial setup and deployment:
|
87
|
+
|
88
|
+
```sh
|
89
|
+
# Provision infrastructure (one-time-only for new apps) using templates.
|
90
|
+
cpl setup-app -a my-app-staging
|
91
|
+
|
92
|
+
# Build and push image with auto-tagging, e.g., "my-app-staging:1_456".
|
93
|
+
cpl build-image -a my-app-staging --commit 456
|
94
|
+
|
95
|
+
# Prepare database.
|
96
|
+
cpl run:detached -a my-app-staging --image latest -- rails db:prepare
|
97
|
+
|
98
|
+
# Deploy latest image.
|
99
|
+
cpl deploy-image -a my-app-staging
|
100
|
+
|
101
|
+
# Open app in browser.
|
102
|
+
cpl open -a my-app-staging
|
103
|
+
```
|
104
|
+
|
105
|
+
Then for promoting code upgrades:
|
106
|
+
|
107
|
+
```sh
|
108
|
+
# Build and push new image with sequential tagging, e.g., "my-app-staging:2".
|
109
|
+
cpl build-image -a my-app-staging
|
110
|
+
|
111
|
+
# Or build and push new image with sequential tagging and commit SHA, e.g., "my-app-staging:2_ABC".
|
112
|
+
cpl build-image -a my-app-staging --commit ABC
|
113
|
+
|
114
|
+
# Run database migrations (or other release tasks) with latest image, while app is still running on previous image.
|
115
|
+
# This is analogous to the release phase.
|
116
|
+
cpl run:detached -a my-app-staging --image latest -- rails db:migrate
|
117
|
+
|
118
|
+
# Deploy latest image.
|
119
|
+
cpl deploy-image -a my-app-staging
|
120
|
+
```
|
121
|
+
|
122
|
+
### Review Special Gems
|
123
|
+
|
124
|
+
Make sure to review "special" gems which might be related to Heroku, e.g.:
|
125
|
+
|
126
|
+
- `rails_autoscale_agent`. It's specific to Heroku, so it must be removed.
|
127
|
+
- `puma_worker_killer`. In general, it's unnecessary on Control Plane, as Kubernetes containers will restart on their
|
128
|
+
own logic and may not restart at all if everything is ok.
|
129
|
+
- `rack-timeout`. It could possibly be replaced with Control Plane's `timeout` option.
|
130
|
+
|
131
|
+
You can use the `CONTROLPLANE` env var to separate the gems, e.g.:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
# Gemfile
|
135
|
+
group :staging, :production do
|
136
|
+
gem "rack-timeout"
|
137
|
+
|
138
|
+
unless ENV.key?("CONTROLPLANE")
|
139
|
+
gem "rails_autoscale_agent"
|
140
|
+
gem "puma_worker_killer"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
```
|
144
|
+
|
145
|
+
### Create a Minimum Bootable Config
|
146
|
+
|
147
|
+
You can try to create a minimum bootable config to migrate parts of your app gradually. To do that, follow these steps:
|
148
|
+
|
149
|
+
1. Rename the existing `application.yml` file to some other name (e.g., `application.old.yml`)
|
150
|
+
2. Create a new **minimal** `application.yml` file, e.g.:
|
151
|
+
|
152
|
+
```yaml
|
153
|
+
SECRET_KEY_BASE: "123"
|
154
|
+
# This should be enabled for `rails s`, not `rails assets:precompile`.
|
155
|
+
# DATABASE_URL: postgres://localhost:5432/dbname
|
156
|
+
# RAILS_SERVE_STATIC_FILES: "true"
|
157
|
+
|
158
|
+
# You will add whatever env vars are required here later.
|
159
|
+
```
|
160
|
+
|
161
|
+
3. Try running `RAILS_ENV=production CONTROLPLANE=true rails assets:precompile`
|
162
|
+
(theoretically, this should work without any additional env vars)
|
163
|
+
4. Fix whatever code needs to be fixed and add missing env vars
|
164
|
+
(the fewer env vars are needed, the cleaner the `Dockerfile` will be)
|
165
|
+
5. Enable `DATABASE_URL` and `RAILS_SERVE_STATIC_FILES` env vars
|
166
|
+
6. Try running `RAILS_ENV=production CONTROLPLANE=true rails s`
|
167
|
+
7. Fix whatever code needs to be fixed and add required env vars to `application.yml`
|
168
|
+
8. Try running your **production** entrypoint command, e.g.,
|
169
|
+
`RAILS_ENV=production RACK_ENV=production CONTROLPLANE=true puma -C config/puma.rb`
|
170
|
+
9. Fix whatever code needs to be fixed and add required env vars to `application.yml`
|
171
|
+
|
172
|
+
Now you should have a minimal bootable config.
|
173
|
+
|
174
|
+
Then you can temporarily set the `LOG_LEVEL=debug` env var and disable unnecessary services to help with the process,
|
175
|
+
e.g.:
|
176
|
+
|
177
|
+
```yaml
|
178
|
+
DISABLE_SPRING: "true"
|
179
|
+
SCOUT_MONITOR: "false"
|
180
|
+
RACK_TIMEOUT_SERVICE_TIMEOUT: "0"
|
181
|
+
```
|
182
|
+
|
183
|
+
## Create the Review App Process
|
184
|
+
|
185
|
+
Add an entry for review apps to the `.controlplane/controlplane.yml` file. By adding a `match_if_app_name_starts_with`
|
186
|
+
key with the value `true`, any app that starts with the entry's name will use this config. Doing this allows you to
|
187
|
+
configure an entry for, e.g., `my-app-review`, and then create review apps starting with that name (e.g.,
|
188
|
+
`my-app-review-1234`, `my-app-review-5678`, etc.). Here's an example:
|
189
|
+
|
190
|
+
```yaml
|
191
|
+
my-app-review:
|
192
|
+
<<: *common
|
193
|
+
match_if_app_name_starts_with: true
|
194
|
+
setup:
|
195
|
+
- gvc
|
196
|
+
- redis
|
197
|
+
- memcached
|
198
|
+
- rails
|
199
|
+
- sidekiq
|
200
|
+
```
|
201
|
+
|
202
|
+
In your CI scripts, you can create a review app using some identifier (e.g., the number of the PR on GitHub).
|
203
|
+
|
204
|
+
```yaml
|
205
|
+
# On CircleCI, you can use `echo $CIRCLE_PULL_REQUEST | grep -Eo '[0-9]+$'` to extract the number of the PR.
|
206
|
+
PR_NUM=$(... extract the number of the PR here ...)
|
207
|
+
echo "export APP_NAME=my-app-review-$PR_NUM" >> $BASH_ENV
|
208
|
+
|
209
|
+
# Only create the app if it doesn't exist yet, as we may have multiple triggers for the review app
|
210
|
+
# (such as when a PR gets updated).
|
211
|
+
if ! cpl exists -a ${APP_NAME}; then
|
212
|
+
cpl setup-app -a ${APP_NAME}
|
213
|
+
echo "export NEW_APP=true" >> $BASH_ENV
|
214
|
+
fi
|
215
|
+
|
216
|
+
# The `NEW_APP` env var that we exported above can be used to either reset or migrate the database before deploying.
|
217
|
+
if [ -n "${NEW_APP}" ]; then
|
218
|
+
cpl run:detached 'LOG_LEVEL=warn rails db:reset' -a ${APP_NAME} --image latest
|
219
|
+
else
|
220
|
+
cpl run:detached 'LOG_LEVEL=warn rails db:migrate_and_wait_replica' -a ${APP_NAME} --image latest
|
221
|
+
fi
|
222
|
+
```
|
223
|
+
|
224
|
+
Then follow the same steps for the initial deployment or code upgrades.
|
225
|
+
|
226
|
+
### Database for Review Apps
|
227
|
+
|
228
|
+
For the review app resources, these should be handled as env vars in the template for the app
|
229
|
+
(`.controlplane/templates/gvc.yml`), .e.g.:
|
230
|
+
|
231
|
+
```yaml
|
232
|
+
- name: DATABASE_URL
|
233
|
+
value: postgres://postgres:XXXXXXXX@cpln-XXXX-staging.XXXXXX.us-east-1.rds.amazonaws.com:5432/APP_GVC
|
234
|
+
```
|
235
|
+
|
236
|
+
Notice that `APP_GVC` is the app name, which is used as the database name on RDS, so that each review app gets its own
|
237
|
+
database on the one RDS instance used for all review apps, which would be, e.g., `my-app-review-1234`.
|
238
|
+
|
239
|
+
### Redis and Memcached for Review Apps
|
240
|
+
|
241
|
+
So long as no persistence is needed for Redis and Memcached, we have templates for workloads that should be sufficient
|
242
|
+
for review apps in the `templates/` directory of this repository. Using these templates results in considerable cost
|
243
|
+
savings compared to paying for the resources on Heroku.
|
244
|
+
|
245
|
+
```yaml
|
246
|
+
- name: MEMCACHE_SERVERS
|
247
|
+
value: memcached.APP_GVC.cpln.local
|
248
|
+
- name: REDIS_URL
|
249
|
+
value: redis://redis.APP_GVC.cpln.local:6379
|
250
|
+
```
|
251
|
+
|
252
|
+
## Deploy to Production
|
253
|
+
|
254
|
+
Only try deploying to production once staging and review apps are working well.
|
255
|
+
|
256
|
+
For simplicity, keep add-ons running on Heroku initially. You could move over the database to RDS first. However, it's a
|
257
|
+
bit simpler to isolate any differences in cost and performance by first moving over your compute to Control Plane.
|
258
|
+
|
259
|
+
Ensure that your Control Plane compute is in the AWS region `US-EAST-1`; otherwise, you'll have noticeable extra latency
|
260
|
+
with your calls to resources. You might also have egress charges from Control Plane.
|
261
|
+
|
262
|
+
Use the `cpl promote-app-from-upstream` command to promote the staging app to production.
|
data/lib/command/ps_start.rb
CHANGED
@@ -42,9 +42,7 @@ module Command
|
|
42
42
|
|
43
43
|
@workloads.reverse_each do |workload|
|
44
44
|
step("Waiting for workload '#{workload}' to be ready", retry_on_failure: true) do
|
45
|
-
cp.
|
46
|
-
item.dig("status", "ready")
|
47
|
-
end
|
45
|
+
cp.workload_deployments_ready?(workload, expected_status: true)
|
48
46
|
end
|
49
47
|
end
|
50
48
|
end
|
data/lib/command/ps_stop.rb
CHANGED
@@ -6,7 +6,7 @@ module Command
|
|
6
6
|
OPTIONS = [
|
7
7
|
app_option(required: true),
|
8
8
|
workload_option,
|
9
|
-
wait_option("workload to be
|
9
|
+
wait_option("workload to not be ready")
|
10
10
|
].freeze
|
11
11
|
DESCRIPTION = "Stops workloads in app"
|
12
12
|
LONG_DESCRIPTION = <<~DESC
|
@@ -41,10 +41,8 @@ module Command
|
|
41
41
|
progress.puts
|
42
42
|
|
43
43
|
@workloads.each do |workload|
|
44
|
-
step("Waiting for workload '#{workload}' to be
|
45
|
-
cp.
|
46
|
-
!item.dig("status", "ready")
|
47
|
-
end
|
44
|
+
step("Waiting for workload '#{workload}' to not be ready", retry_on_failure: true) do
|
45
|
+
cp.workload_deployments_ready?(workload, expected_status: false)
|
48
46
|
end
|
49
47
|
end
|
50
48
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Command
|
4
|
+
class PsWait < Base
|
5
|
+
NAME = "ps:wait"
|
6
|
+
OPTIONS = [
|
7
|
+
app_option(required: true),
|
8
|
+
workload_option
|
9
|
+
].freeze
|
10
|
+
DESCRIPTION = "Waits for workloads in app to be ready after re-deployment"
|
11
|
+
LONG_DESCRIPTION = <<~DESC
|
12
|
+
- Waits for workloads in app to be ready after re-deployment
|
13
|
+
DESC
|
14
|
+
EXAMPLES = <<~EX
|
15
|
+
```sh
|
16
|
+
# Waits for all workloads in app.
|
17
|
+
cpl ps:wait -a $APP_NAME
|
18
|
+
|
19
|
+
# Waits for a specific workload in app.
|
20
|
+
cpl ps:swait -a $APP_NAME -w $WORKLOAD_NAME
|
21
|
+
```
|
22
|
+
EX
|
23
|
+
|
24
|
+
def call
|
25
|
+
@workloads = [config.options[:workload]] if config.options[:workload]
|
26
|
+
@workloads ||= config[:app_workloads] + config[:additional_workloads]
|
27
|
+
|
28
|
+
@workloads.reverse_each do |workload|
|
29
|
+
step("Waiting for workload '#{workload}' to be ready", retry_on_failure: true) do
|
30
|
+
cp.workload_deployments_ready?(workload, expected_status: true)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/core/controlplane.rb
CHANGED
@@ -149,6 +149,26 @@ class Controlplane # rubocop:disable Metrics/ClassLength
|
|
149
149
|
api.workload_deployments(workload: workload, gvc: gvc, org: org)
|
150
150
|
end
|
151
151
|
|
152
|
+
def workload_deployment_version_ready?(version, next_version, expected_status:)
|
153
|
+
return false unless version["workload"] == next_version
|
154
|
+
|
155
|
+
version["containers"]&.all? do |_, container|
|
156
|
+
ready = container.dig("resources", "replicas") == container.dig("resources", "replicasReady")
|
157
|
+
expected_status == true ? ready : !ready
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def workload_deployments_ready?(workload, expected_status:)
|
162
|
+
deployments = fetch_workload_deployments(workload)["items"]
|
163
|
+
deployments.all? do |deployment|
|
164
|
+
next_version = deployment.dig("status", "expectedDeploymentVersion")
|
165
|
+
|
166
|
+
deployment.dig("status", "versions")&.all? do |version|
|
167
|
+
workload_deployment_version_ready?(version, next_version, expected_status: expected_status)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
152
172
|
def workload_set_image_ref(workload, container:, image:)
|
153
173
|
cmd = "cpln workload update #{workload} #{gvc_org}"
|
154
174
|
cmd += " --set spec.containers.#{container}.image=/org/#{config.org}/image/#{image}"
|
data/lib/cpl/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cpl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Gordon
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2023-
|
12
|
+
date: 2023-07-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: debug
|
@@ -223,6 +223,7 @@ files:
|
|
223
223
|
- docs/assets/memcached.png
|
224
224
|
- docs/assets/sidekiq-pre-stop-hook.png
|
225
225
|
- docs/commands.md
|
226
|
+
- docs/migrating.md
|
226
227
|
- docs/postgres.md
|
227
228
|
- docs/redis.md
|
228
229
|
- docs/tips.md
|
@@ -255,6 +256,7 @@ files:
|
|
255
256
|
- lib/command/ps_restart.rb
|
256
257
|
- lib/command/ps_start.rb
|
257
258
|
- lib/command/ps_stop.rb
|
259
|
+
- lib/command/ps_wait.rb
|
258
260
|
- lib/command/run.rb
|
259
261
|
- lib/command/run_cleanup.rb
|
260
262
|
- lib/command/run_detached.rb
|