shippy 0.2.8 â 0.2.9
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 +219 -7
- data/lib/shippy/cli/templates/config/shippy.yml +0 -1
- data/lib/shippy/compose.rb +1 -1
- data/lib/shippy/service.rb +1 -1
- data/lib/shippy/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c8a547859425588ab2d87d11010d8650d8b1d5ee67b6abe1239aa1215c8799ed
|
|
4
|
+
data.tar.gz: bab2f41d53d11eda45e4e7e70d09bda20e09d2ca6d239a1d0985c3d796a62766
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c44eaa3a47d6e8c13c43d41a4fc676e9c9347459c15ef7c4e44ed134c9b99e15d8dfcb6934a82313b1840c7ee69ad450555890de26cd8b4ac94f436ea0daff79
|
|
7
|
+
data.tar.gz: 534231ef52cb40213a44c969f53c4f479f6573a5a299c3a03ac5327ba2be4a2e8dec1591ccc56c4ae5f5c85d96c87c41b3274c09d5139242adf727999eb373c1
|
data/README.md
CHANGED
|
@@ -2,14 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
Shippy is a lightweight container orchestration tool designed specifically for homelabs. It combines the simplicity of Docker Compose with a powerful Ruby DSL, inspired by the deployment workflows of Capistrano and Kamal.
|
|
4
4
|
|
|
5
|
-
## Features
|
|
5
|
+
## ⨠Features
|
|
6
6
|
|
|
7
|
-
- Ruby DSL to generate
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
7
|
+
- Ruby DSL to generate cleaner, DRYer docker-compose.yml files.
|
|
8
|
+
- Server bootstrapping to automatically provision a raw server with Docker and necessary dependencies.
|
|
9
|
+
- Built-in rollbacks to afely revert to previous deployments with a single command.
|
|
10
|
+
- Immutable deployments which automatically pins image digests (sha256) during deployment to prevent upstream changes from breaking your apps.
|
|
11
|
+
- Centralized secrets for securely defining and injecting encrypted credentials.
|
|
12
|
+
- First-class Traefik support comes as a built-in reverse proxy routing with SSL wildcard certificate generation.
|
|
13
|
+
- Garbage collection which defines prune commands to keep your homelab server's storage clean.
|
|
11
14
|
|
|
12
|
-
## đ Getting
|
|
15
|
+
## đ Getting started
|
|
13
16
|
|
|
14
17
|
Install the gem:
|
|
15
18
|
|
|
@@ -17,7 +20,7 @@ Install the gem:
|
|
|
17
20
|
$ gem install shippy
|
|
18
21
|
```
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
Make your homelab directory:
|
|
21
24
|
|
|
22
25
|
```shell
|
|
23
26
|
home$ mkdir homelab && cd homelab
|
|
@@ -29,6 +32,48 @@ This creates the core structure:
|
|
|
29
32
|
- `config/`: Shippy configuration and secrets.
|
|
30
33
|
- `bin/shippy`: Your local entry point for all commands.
|
|
31
34
|
|
|
35
|
+
### đ ī¸ Provision & deploy
|
|
36
|
+
|
|
37
|
+
Shippy can automatically prepare a brand new Ubuntu/Debian server for you. Once your `config/shippy.yml` is configured with your host IP and SSH details, run:
|
|
38
|
+
|
|
39
|
+
```shell
|
|
40
|
+
homelab$ bin/shippy setup
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
This command will:
|
|
44
|
+
|
|
45
|
+
- Log into your server and install `curl`, `docker.io`, and `docker-compose` via `apt-get` (if missing).
|
|
46
|
+
- Create the required directory structures (`apps/` and `backups/`).
|
|
47
|
+
- Deploy all of your configured apps.
|
|
48
|
+
|
|
49
|
+
### đšī¸ CLI commands & app management
|
|
50
|
+
|
|
51
|
+
Shippy features both global commands (for the whole lab) and granular commands (for specific apps).
|
|
52
|
+
|
|
53
|
+
Global commands:
|
|
54
|
+
|
|
55
|
+
- `bin/shippy deploy` - Deploys or updates all applications in your `apps/` directory.
|
|
56
|
+
- `bin/shippy stop` - Stops all applications.
|
|
57
|
+
- `bin/shippy refresh` - Pulls the latest images and restarts all services.
|
|
58
|
+
- `bin/shippy prune all` - Cleans up unused images (older than 7 days) and stopped containers (older than 3 days).
|
|
59
|
+
|
|
60
|
+
Granular app commands (`bin/shippy app <command> <name>`):
|
|
61
|
+
|
|
62
|
+
- `bin/shippy app deploy proxy` - Deploys only the `proxy` app.
|
|
63
|
+
- `bin/shippy app logs proxy --follow` - Tails the logs for the proxy app.
|
|
64
|
+
- `bin/shippy app restart proxy --service traefik` - Restarts only the specific traefik service inside the proxy app.
|
|
65
|
+
- `bin/shippy app status proxy` - Shows the current ps status of the app's containers.
|
|
66
|
+
- `bin/shippy app compile proxy` - Generates the files that would be copied to the server in the `builds/apps/proxy/` directory, useful for debugging the files without actually deploying them.
|
|
67
|
+
|
|
68
|
+
### âĒ Instant rollbacks
|
|
69
|
+
|
|
70
|
+
Because Shippy backs up your previous deployment directories (configurable via `keep_releases`), you can easily roll back if an update breaks your app:
|
|
71
|
+
|
|
72
|
+
```shell
|
|
73
|
+
# Rollback the proxy app by 1 version
|
|
74
|
+
bin/shippy app rollback proxy -n 1
|
|
75
|
+
```
|
|
76
|
+
|
|
32
77
|
### Docker compose DSL:
|
|
33
78
|
|
|
34
79
|
Conventions:
|
|
@@ -76,6 +121,173 @@ By running `bin/shippy deploy proxy` the DSL gets converted to YAML and deployed
|
|
|
76
121
|
|
|
77
122
|
See the examples directory for more options.
|
|
78
123
|
|
|
124
|
+
### âī¸ Configuration
|
|
125
|
+
|
|
126
|
+
Shippy uses a central configuration file (located at `config/shippy.yml`) to define your lab environment.
|
|
127
|
+
|
|
128
|
+
#### Global Settings
|
|
129
|
+
|
|
130
|
+
Here is an example configuration:
|
|
131
|
+
|
|
132
|
+
```yaml
|
|
133
|
+
host: 'homelab.local'
|
|
134
|
+
ssh:
|
|
135
|
+
user: name
|
|
136
|
+
wildcard_domain: 'lab.example.com'
|
|
137
|
+
deploy_to: '/var/lib/homelab'
|
|
138
|
+
secrets_file: 'config/secrets.yml.enc'
|
|
139
|
+
keep_releases: 5
|
|
140
|
+
media_path: '/media/storage'
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Shippy is designed to automatically secure your services with a wildcard SSL certificate (`*.lab.example.com`). To achieve this, it relies on a `DNS-01` challenge.
|
|
144
|
+
|
|
145
|
+
* You must use Cloudflare as your DNS provider so Traefik can automatically verify domain ownership via their API.
|
|
146
|
+
* You need to configure a wildcard DNS record (`*.lab.example.com`) in Cloudflare pointing to the IP address of your homelab server.
|
|
147
|
+
|
|
148
|
+
#### Secrets management
|
|
149
|
+
|
|
150
|
+
Your secrets are stored in an encrypted file defined by secrets_file (e.g., `config/secrets.yml.enc`).
|
|
151
|
+
|
|
152
|
+
Secrets in this file are scoped to the specific app they belong to. For example, if you have an app named `proxy`, your secrets file structure should look like this:
|
|
153
|
+
|
|
154
|
+
```yaml
|
|
155
|
+
proxy:
|
|
156
|
+
cloudflare_email: "user@example.com"
|
|
157
|
+
cloudflare_token: "your-api-token"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Inside your `apps/proxy/docker-compose.rb`, calling `secrets(:cloudflare_email)` will fetch the value specifically nested under the proxy key. This ensures services only have access to their own credentials.
|
|
161
|
+
|
|
162
|
+
Run `bin/shippy secrets edit` to safely modify them using your default `$EDITOR`.
|
|
163
|
+
|
|
164
|
+
â ī¸ Secrets are only encrypted at rest within the `config/secrets.yml.enc` file. During compilation and deployment, these secrets are injected as plaintext into the generated `docker-compose.yml` files and will be visible in your local `builds/` directory. The primary intent of this feature is to allow you to safely commit your homelab configuration to Git without exposing keys in your repository, not to provide strict, enterprise-grade runtime security. There is an open issue to integrate natively with Docker Compose secrets [here](https://gitlab.com/mrbobin/shippy/-/issues/1).
|
|
165
|
+
|
|
166
|
+
#### đĻ Exposing Apps (Traefik)
|
|
167
|
+
|
|
168
|
+
To make an app accessible from the outside world, use the `use_traefik` helper inside your service block.
|
|
169
|
+
|
|
170
|
+
```ruby
|
|
171
|
+
use_traefik(name: 'home-assistant', port: 8123)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
This automatically generates the labels required to expose the container at `home-assistant.lab.example.com`.
|
|
175
|
+
|
|
176
|
+
- The name dictates the subdomain.
|
|
177
|
+
- The port is optional if your container only exposes a single port, but it __should be explicitly defined__ if the container exposes multiple internal ports.
|
|
178
|
+
|
|
179
|
+
Sometimes you need more complex routing than just matching the host. You can pass a block to use_traefik to append custom Traefik routing rules.
|
|
180
|
+
|
|
181
|
+
```ruby
|
|
182
|
+
use_traefik(name: 'matrix', port: 80) do |rule|
|
|
183
|
+
"#{rule} && PathPrefix(`/.well-known/`)"
|
|
184
|
+
end
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
If a single container provides multiple web interfaces (like MinIO, which has an API and a web console), you can manually build and append the Traefik labels using `build_traefik_labels`:
|
|
188
|
+
|
|
189
|
+
```ruby
|
|
190
|
+
labels do
|
|
191
|
+
all_labels = ["traefik.enable=true"]
|
|
192
|
+
all_labels += build_traefik_labels(name: :minio, port: 9000)
|
|
193
|
+
all_labels += build_traefik_labels(name: :mconsole, port: 9001)
|
|
194
|
+
|
|
195
|
+
all_labels
|
|
196
|
+
end
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
#### đ Overriding defaults
|
|
200
|
+
|
|
201
|
+
To keep your files clean, Shippy provides a `use_default_option`s method. Calling this automatically applies default Docker networks for Traefik access, a standard restart policy (like `unless-stopped`), and default logging limits so your drives don't fill up.
|
|
202
|
+
|
|
203
|
+
If you need fine-grained control, you can omit `use_default_options` and specify exactly what you want:
|
|
204
|
+
|
|
205
|
+
```ruby
|
|
206
|
+
networks { [ 'backend', 'lan_access' ] } # 'lan_access' is required by Traefik(if used on the service)
|
|
207
|
+
use_default_restart
|
|
208
|
+
use_default_logging
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
This is highly useful when placing an app on an isolated network without exposing it to the default network.
|
|
212
|
+
|
|
213
|
+
#### Post-deployment hooks
|
|
214
|
+
|
|
215
|
+
Sometimes a container needs to run commands immediately after it boots up (like database migrations or setting up initial admin users). You can define an array of commands in a `hooks` block, and Shippy will execute them sequentially inside the running container:
|
|
216
|
+
|
|
217
|
+
```ruby
|
|
218
|
+
hooks do
|
|
219
|
+
[
|
|
220
|
+
'bundle exec rails db:create',
|
|
221
|
+
'bundle exec rails db:migrate'
|
|
222
|
+
]
|
|
223
|
+
end
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
#### DRY service configurations
|
|
227
|
+
|
|
228
|
+
Shippy allows you to define custom helper methods directly inside the `Shippy.define` block to share logic across multiple services.
|
|
229
|
+
|
|
230
|
+
- Use `x.<key>` to access variables from your global config file (like `x.media_path`).
|
|
231
|
+
- Use `app.<method_name>` to call your custom methods from inside a service block.
|
|
232
|
+
|
|
233
|
+
```ruby
|
|
234
|
+
Shippy.define do
|
|
235
|
+
# 1. Define a shared helper method
|
|
236
|
+
def nextcloud_volumes
|
|
237
|
+
[
|
|
238
|
+
# 'x' accesses properties from your global config file
|
|
239
|
+
"#{x.media_path}/nextcloud/html:/var/www/html",
|
|
240
|
+
"#{x.media_path}/nextcloud/apps:/var/www/html/custom_apps",
|
|
241
|
+
"#{x.media_path}/nextcloud/config:/var/www/html/config",
|
|
242
|
+
"#{x.media_path}/nextcloud/data:/var/www/html/data",
|
|
243
|
+
"#{x.media_path}/nextcloud/themes:/var/www/html/themes"
|
|
244
|
+
]
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
service :nextcloud do
|
|
248
|
+
image { 'nextcloud:fpm-alpine' }
|
|
249
|
+
|
|
250
|
+
# 2. Call the helper method using 'app'
|
|
251
|
+
volumes { app.nextcloud_volumes }
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
service :nextcloud_proxy do
|
|
255
|
+
image { 'nginx:alpine' }
|
|
256
|
+
depends_on { ['nextcloud'] }
|
|
257
|
+
|
|
258
|
+
# 3. Combine unique volumes with the shared volumes array
|
|
259
|
+
volumes { ["./nginx/nginx.conf:/etc/nginx/nginx.conf"] + app.nextcloud_volumes }
|
|
260
|
+
use_traefik(name: 'box')
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
#### App files & ERB templating
|
|
266
|
+
|
|
267
|
+
Any files or directories you place inside an app's directoy (alongside `docker-compose.rb`) are automatically copied over to your homelab server during deployment. This makes it incredibly easy to bundle configuration files (like Nginx confs, Prometheus rules, or Traefik configs) right next to the service that uses them.
|
|
268
|
+
|
|
269
|
+
However, there are two crucial rules to understand about how Shippy handles these files:
|
|
270
|
+
|
|
271
|
+
1. Avoid bind mounting to the app directory
|
|
272
|
+
Because Shippy keeps track of your deployment history (using the `keep_releases` setting in your config), the actual directory where your app runs gets rotated and moved to a backups path on every deploy. Do not use relative bind mounts for data that changes or needs to persist (e.g., `./data:/var/lib/mysql`). When you deploy again, the folder moves, and your container will start with a fresh, empty directory! Always bind mount your persistent data to a stable, absolute path on your server, such as the `media_path` defined in your `shippy.yml`, or use standard Docker named volumes.
|
|
273
|
+
|
|
274
|
+
2. ERB templating for dynamic configs
|
|
275
|
+
Shippy allows you to use Ruby's ERB templating inside your supplemental files. If you need to inject secrets, loop through configurations, or access global variables, simply append `.erb` to the file name.
|
|
276
|
+
During deployment, Shippy will evaluate the Ruby code, strip the `.erb` extension, and upload the fully rendered file to your server.
|
|
277
|
+
|
|
278
|
+
Example: `apps/proxy/traefik/config.yml.erb` In this Traefik config, we can securely inject the Cloudflare email right from our encrypted `secrets.yml.enc` file:
|
|
279
|
+
|
|
280
|
+
```yaml
|
|
281
|
+
certificatesResolvers:
|
|
282
|
+
ssl-resolver:
|
|
283
|
+
acme:
|
|
284
|
+
# Shippy dynamically injects this secret during deploy!
|
|
285
|
+
email: <%= secrets(:cloudflare_email) %>
|
|
286
|
+
storage: /etc/traefik/acme/acme.json
|
|
287
|
+
dnsChallenge:
|
|
288
|
+
provider: cloudflare
|
|
289
|
+
```
|
|
290
|
+
|
|
79
291
|
## Development
|
|
80
292
|
|
|
81
293
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/shippy/compose.rb
CHANGED
data/lib/shippy/service.rb
CHANGED
data/lib/shippy/version.rb
CHANGED