detached a9c1886

docs: rewrite CI/CD deployment guides with gordon push as recommended method

- deployment/index.md: decision matrix for 3 push methods, network topology guide, token scopes reference
- deployment/github-actions.md: add gordon push workflow examples, fix checkout@v6 to v4, add docker-based alternative
- deployment/gitlab-ci.md: new guide for GitLab CI/CD pipelines
- deployment/generic-ci.md: new guide for Jenkins, CircleCI, Drone, and other CI systems
- cli/push.md: update synopsis to [image], add auth/version auto-detection/CI sections
- index.md: add GitLab CI and Generic CI navigation links
commit
a9c18869026b065d13eddd3ee0b65085fa14baa2
author
bnema · · 2026-03-18 21:48 UTC
parent
da431e6
signature
unsigned
6 files · +822 -183
M docs/cli/push.md +51 -12
@@ -7,14 +7,14 @@ Tag, push, and optionally deploy an image to the Gordon registry.
77 ### Synopsis
88
99 ```bash
10-gordon push <domain> [options]
10+gordon push [image] [options]
1111 ```
1212
1313 ### Arguments
1414
1515 | Argument | Description |
1616 |----------|-------------|
17-| `<domain>` | The route domain to resolve the registry and repository from |
17+| `[image]` | Image name to push (optional). If omitted, auto-detected from Dockerfile labels or current directory name |
1818
1919 ### Options
2020
@@ -27,14 +27,20 @@ gordon push <domain> [options]
2727 | `--tag` | Override version tag (default: tag ref from CI, then `git describe --tags --dirty`) |
2828 | `--no-confirm` | Skip deploy confirmation prompt |
2929 | `--no-deploy` | Push only; skip deployment prompt |
30+| `--domain` | Explicit domain override (legacy mode) |
3031 | `--remote` | Remote Gordon URL |
3132 | `--token` | Authentication token for remote |
3233
3334 ### Description
3435
35-`gordon push` resolves the route image for `<domain>`, tags the image for the
36+`gordon push` resolves the target image from the backend, tags it for the
3637 Gordon registry, pushes it, and optionally deploys it.
3738
39+Image resolution order:
40+1. If `--domain` is provided, uses domain-based route lookup
41+2. If an image name is provided as argument, resolves domain(s) from the backend
42+3. If no argument, auto-detects from Dockerfile `gordon.domain` label or current directory name
43+
3844 To push attachment images (databases, caches, etc.), use `gordon attachments push`.
3945
4046 - For first deploys, run `gordon bootstrap` first to create or update the route, attachments, and secrets, then run `gordon push` to upload and deploy the image.
@@ -43,33 +49,64 @@ To push attachment images (databases, caches, etc.), use `gordon attachments pus
4349 then falls back to `git describe --tags --dirty` (for example
4450 `v1.2.3-4-gabc1234` or `v1.2.3-dirty`). If no tag is found, `latest` is used.
4551 - When `--build` is set, the command builds with `docker buildx build --load`
46- and injects `VERSION` into the build environment plus any `--build-arg` values.
52+ and injects `VERSION`, `GIT_TAG`, `GIT_SHA`, and `BUILD_TIME` into the build
53+ environment plus any `--build-arg` values.
4754 - Use `-f/--file` to build from a Dockerfile outside the current directory root.
4855 - The version tag and `latest` are both pushed (unless the version is `latest`).
4956
57+### Authentication
58+
59+When used with `--remote`, gordon push authenticates in two ways:
60+
61+- **Admin API** (route resolution, deploy): uses `--token` or `$GORDON_TOKEN` as Bearer token
62+- **Registry push**: automatically exchanges the token for a short-lived (5 min) registry access token via `/auth/token` -- no `docker login` required
63+
64+This means CI/CD pipelines only need a single secret (`GORDON_TOKEN`).
65+
66+### Version Auto-Detection
67+
68+Gordon reads version tags from CI environment variables (in priority order):
69+
70+| CI System | Variable | Example |
71+|-----------|----------|---------|
72+| GitHub Actions | `$GITHUB_REF` | `refs/tags/v1.2.0` |
73+| GitHub Actions | `$GITHUB_REF_TYPE` + `$GITHUB_REF_NAME` | `tag` + `v1.2.0` |
74+| GitLab CI | `$CI_COMMIT_TAG` | `v1.2.0` |
75+| Azure DevOps | `$BUILD_SOURCEBRANCH` | `refs/tags/v1.2.0` |
76+| Any | `git describe --tags` | `v1.2.3-4-gabc1234` |
77+| Fallback | - | `latest` |
78+
5079 ### Examples
5180
5281 ```bash
53-# Build, push, and deploy
54-gordon push myapp.example.com --build
82+# Build, push, and deploy (auto-detect image name)
83+gordon push --build --remote https://gordon.example.com --no-confirm
84+
85+# Specify image name explicitly
86+gordon push myapp --build --remote https://gordon.example.com --no-confirm
5587
5688 # Push existing local image, skip deploy
57-gordon push myapp.example.com --tag v1.2.0 --no-deploy
89+gordon push myapp --tag v1.2.0 --no-deploy
5890
5991 # Push and deploy without confirmation
60-gordon push myapp.example.com --no-confirm
92+gordon push myapp --no-confirm
6193
6294 # Build for ARM and pass build args
63-gordon push myapp.example.com --build --platform linux/arm64 --build-arg CGO_ENABLED=0
95+gordon push myapp --build --platform linux/arm64 --build-arg CGO_ENABLED=0
6496
6597 # Build from a custom Dockerfile path
66-gordon push myapp.example.com --build -f docker/app/Dockerfile
98+gordon push myapp --build -f docker/app/Dockerfile
99+
100+# CI/CD usage (single env var, no docker login needed)
101+export GORDON_TOKEN="your-token"
102+gordon push --build --remote https://gordon.example.com --no-confirm
67103 ```
68104
69105 ### Notes
70106
71107 - Remote mode required. See [CLI Overview](./index.md) for targeting options.
72-- `gordon push` still requires the route to already exist so it can resolve the target image.
108+- `gordon push` requires the route to already exist so it can resolve the target image.
109+ Use `gordon bootstrap` for first deploys.
73110 - `--build` requires Docker with Buildx. Docker Desktop includes it; on Linux,
74111 install the `docker-buildx-plugin` package.
75112 - Gordon uses native registry uploads instead of shelling out to `docker push`.
@@ -81,6 +118,8 @@ gordon push myapp.example.com --build -f docker/app/Dockerfile
81118 ## Related
82119
83120 - [CLI Overview](./index.md)
121+- [Deployment Overview](../deployment/index.md)
122+- [GitHub Actions](../deployment/github-actions.md)
84123 - [Attachments Commands](./attachments.md)
85124 - [Routes Command](./routes.md)
86-- [Serve Command](./serve.md)
125+- [Authentication](../config/auth.md)
@@ -7,14 +7,14 @@ Tag, push, and optionally deploy an image to the Gordon registry.
7 ### Synopsis7 ### Synopsis
8 8
9 ```bash9 ```bash
10-gordon push <domain> [options]10+gordon push [image] [options]
11 ```11 ```
12 12
13 ### Arguments13 ### Arguments
14 14
15 | Argument | Description |15 | Argument | Description |
16 |----------|-------------|16 |----------|-------------|
17-| `<domain>` | The route domain to resolve the registry and repository from |17+| `[image]` | Image name to push (optional). If omitted, auto-detected from Dockerfile labels or current directory name |
18 18
19 ### Options19 ### Options
20 20
@@ -27,14 +27,20 @@ gordon push <domain> [options]
27 | `--tag` | Override version tag (default: tag ref from CI, then `git describe --tags --dirty`) |27 | `--tag` | Override version tag (default: tag ref from CI, then `git describe --tags --dirty`) |
28 | `--no-confirm` | Skip deploy confirmation prompt |28 | `--no-confirm` | Skip deploy confirmation prompt |
29 | `--no-deploy` | Push only; skip deployment prompt |29 | `--no-deploy` | Push only; skip deployment prompt |
30+| `--domain` | Explicit domain override (legacy mode) |
30 | `--remote` | Remote Gordon URL |31 | `--remote` | Remote Gordon URL |
31 | `--token` | Authentication token for remote |32 | `--token` | Authentication token for remote |
32 33
33 ### Description34 ### Description
34 35
35-`gordon push` resolves the route image for `<domain>`, tags the image for the36+`gordon push` resolves the target image from the backend, tags it for the
36 Gordon registry, pushes it, and optionally deploys it.37 Gordon registry, pushes it, and optionally deploys it.
37 38
39+Image resolution order:
40+1. If `--domain` is provided, uses domain-based route lookup
41+2. If an image name is provided as argument, resolves domain(s) from the backend
42+3. If no argument, auto-detects from Dockerfile `gordon.domain` label or current directory name
43+
38 To push attachment images (databases, caches, etc.), use `gordon attachments push`.44 To push attachment images (databases, caches, etc.), use `gordon attachments push`.
39 45
40 - For first deploys, run `gordon bootstrap` first to create or update the route, attachments, and secrets, then run `gordon push` to upload and deploy the image.46 - For first deploys, run `gordon bootstrap` first to create or update the route, attachments, and secrets, then run `gordon push` to upload and deploy the image.
@@ -43,33 +49,64 @@ To push attachment images (databases, caches, etc.), use `gordon attachments pus
43 then falls back to `git describe --tags --dirty` (for example49 then falls back to `git describe --tags --dirty` (for example
44 `v1.2.3-4-gabc1234` or `v1.2.3-dirty`). If no tag is found, `latest` is used.50 `v1.2.3-4-gabc1234` or `v1.2.3-dirty`). If no tag is found, `latest` is used.
45 - When `--build` is set, the command builds with `docker buildx build --load`51 - When `--build` is set, the command builds with `docker buildx build --load`
46- and injects `VERSION` into the build environment plus any `--build-arg` values.52+ and injects `VERSION`, `GIT_TAG`, `GIT_SHA`, and `BUILD_TIME` into the build
53+ environment plus any `--build-arg` values.
47 - Use `-f/--file` to build from a Dockerfile outside the current directory root.54 - Use `-f/--file` to build from a Dockerfile outside the current directory root.
48 - The version tag and `latest` are both pushed (unless the version is `latest`).55 - The version tag and `latest` are both pushed (unless the version is `latest`).
49 56
57+### Authentication
58+
59+When used with `--remote`, gordon push authenticates in two ways:
60+
61+- **Admin API** (route resolution, deploy): uses `--token` or `$GORDON_TOKEN` as Bearer token
62+- **Registry push**: automatically exchanges the token for a short-lived (5 min) registry access token via `/auth/token` -- no `docker login` required
63+
64+This means CI/CD pipelines only need a single secret (`GORDON_TOKEN`).
65+
66+### Version Auto-Detection
67+
68+Gordon reads version tags from CI environment variables (in priority order):
69+
70+| CI System | Variable | Example |
71+|-----------|----------|---------|
72+| GitHub Actions | `$GITHUB_REF` | `refs/tags/v1.2.0` |
73+| GitHub Actions | `$GITHUB_REF_TYPE` + `$GITHUB_REF_NAME` | `tag` + `v1.2.0` |
74+| GitLab CI | `$CI_COMMIT_TAG` | `v1.2.0` |
75+| Azure DevOps | `$BUILD_SOURCEBRANCH` | `refs/tags/v1.2.0` |
76+| Any | `git describe --tags` | `v1.2.3-4-gabc1234` |
77+| Fallback | - | `latest` |
78+
50 ### Examples79 ### Examples
51 80
52 ```bash81 ```bash
53-# Build, push, and deploy82+# Build, push, and deploy (auto-detect image name)
54-gordon push myapp.example.com --build83+gordon push --build --remote https://gordon.example.com --no-confirm
84+
85+# Specify image name explicitly
86+gordon push myapp --build --remote https://gordon.example.com --no-confirm
55 87
56 # Push existing local image, skip deploy88 # Push existing local image, skip deploy
57-gordon push myapp.example.com --tag v1.2.0 --no-deploy89+gordon push myapp --tag v1.2.0 --no-deploy
58 90
59 # Push and deploy without confirmation91 # Push and deploy without confirmation
60-gordon push myapp.example.com --no-confirm92+gordon push myapp --no-confirm
61 93
62 # Build for ARM and pass build args94 # Build for ARM and pass build args
63-gordon push myapp.example.com --build --platform linux/arm64 --build-arg CGO_ENABLED=095+gordon push myapp --build --platform linux/arm64 --build-arg CGO_ENABLED=0
64 96
65 # Build from a custom Dockerfile path97 # Build from a custom Dockerfile path
66-gordon push myapp.example.com --build -f docker/app/Dockerfile98+gordon push myapp --build -f docker/app/Dockerfile
99+
100+# CI/CD usage (single env var, no docker login needed)
101+export GORDON_TOKEN="your-token"
102+gordon push --build --remote https://gordon.example.com --no-confirm
67 ```103 ```
68 104
69 ### Notes105 ### Notes
70 106
71 - Remote mode required. See [CLI Overview](./index.md) for targeting options.107 - Remote mode required. See [CLI Overview](./index.md) for targeting options.
72-- `gordon push` still requires the route to already exist so it can resolve the target image.108+- `gordon push` requires the route to already exist so it can resolve the target image.
109+ Use `gordon bootstrap` for first deploys.
73 - `--build` requires Docker with Buildx. Docker Desktop includes it; on Linux,110 - `--build` requires Docker with Buildx. Docker Desktop includes it; on Linux,
74 install the `docker-buildx-plugin` package.111 install the `docker-buildx-plugin` package.
75 - Gordon uses native registry uploads instead of shelling out to `docker push`.112 - Gordon uses native registry uploads instead of shelling out to `docker push`.
@@ -81,6 +118,8 @@ gordon push myapp.example.com --build -f docker/app/Dockerfile
81 ## Related118 ## Related
82 119
83 - [CLI Overview](./index.md)120 - [CLI Overview](./index.md)
121+- [Deployment Overview](../deployment/index.md)
122+- [GitHub Actions](../deployment/github-actions.md)
84 - [Attachments Commands](./attachments.md)123 - [Attachments Commands](./attachments.md)
85 - [Routes Command](./routes.md)124 - [Routes Command](./routes.md)
86-- [Serve Command](./serve.md)125+- [Authentication](../config/auth.md)
A docs/deployment/generic-ci.md +204 -0
@@ -0,0 +1,204 @@
1+# Generic CI/CD Deployment
2+
3+Deploy with Gordon from any CI/CD system.
4+
5+## Requirements
6+
7+- Docker available on CI runner (for building images)
8+- Network access to your Gordon server (HTTPS)
9+- Gordon binary (optional but recommended)
10+
11+## Recommended: gordon push
12+
13+### 1. Generate Deployment Token
14+
15+On your Gordon server:
16+
17+```bash
18+gordon auth token generate \
19+ --subject ci-deploy \
20+ --scopes "push,pull,admin:routes:read,admin:config:write" \
21+ --expiry 0
22+```
23+
24+### 2. Configure CI Secrets
25+
26+Add these secrets to your CI system:
27+
28+| Secret | Value |
29+|--------|-------|
30+| `GORDON_TOKEN` | The generated token |
31+| `GORDON_REMOTE` | `https://gordon.example.com` |
32+
33+### 3. Pipeline Steps
34+
35+```bash
36+# 1. Install Gordon binary
37+curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 \
38+ -o /usr/local/bin/gordon
39+chmod +x /usr/local/bin/gordon
40+
41+# 2. Build, push, and deploy
42+export GORDON_TOKEN="$GORDON_TOKEN"
43+gordon push --build \
44+ --remote "$GORDON_REMOTE" \
45+ --no-confirm
46+```
47+
48+Gordon auto-detects the version from CI environment variables:
49+
50+| CI System | Variable | Example |
51+|-----------|----------|---------|
52+| GitHub Actions | `$GITHUB_REF` | `refs/tags/v1.2.0` |
53+| GitLab CI | `$CI_COMMIT_TAG` | `v1.2.0` |
54+| Azure DevOps | `$BUILD_SOURCEBRANCH` | `refs/tags/v1.2.0` |
55+| Other | `--tag` flag | `gordon push --tag v1.2.0` |
56+
57+## Alternative: docker push
58+
59+If installing the Gordon binary is not possible:
60+
61+```bash
62+# 1. Login to Gordon registry
63+echo "$GORDON_TOKEN" | docker login gordon.example.com \
64+ -u ci-deploy --password-stdin
65+
66+# 2. Build and push
67+docker build -t gordon.example.com/myapp:v1.0.0 .
68+docker push gordon.example.com/myapp:v1.0.0
69+```
70+
71+This requires the token subject (`ci-deploy`) as the username.
72+Gordon auto-deploys when it receives the image.
73+
74+## CI System Examples
75+
76+### Jenkins
77+
78+```groovy
79+pipeline {
80+ agent any
81+ environment {
82+ GORDON_TOKEN = credentials('gordon-token')
83+ GORDON_REMOTE = 'https://gordon.example.com'
84+ }
85+ stages {
86+ stage('Deploy') {
87+ steps {
88+ sh '''
89+ curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 \
90+ -o /usr/local/bin/gordon
91+ chmod +x /usr/local/bin/gordon
92+ gordon push --build --remote "$GORDON_REMOTE" --no-confirm
93+ '''
94+ }
95+ }
96+ }
97+}
98+```
99+
100+### CircleCI
101+
102+```yaml
103+version: 2.1
104+
105+jobs:
106+ deploy:
107+ docker:
108+ - image: docker:24
109+ steps:
110+ - checkout
111+ - setup_remote_docker
112+ - run:
113+ name: Install Gordon
114+ command: |
115+ apk add --no-cache curl
116+ curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 \
117+ -o /usr/local/bin/gordon
118+ chmod +x /usr/local/bin/gordon
119+ - run:
120+ name: Deploy
121+ command: |
122+ gordon push --build \
123+ --remote "$GORDON_REMOTE" \
124+ --no-confirm
125+
126+workflows:
127+ deploy:
128+ jobs:
129+ - deploy:
130+ filters:
131+ tags:
132+ only: /^v.*/
133+ branches:
134+ ignore: /.*/
135+```
136+
137+### Drone
138+
139+```yaml
140+kind: pipeline
141+type: docker
142+name: deploy
143+
144+steps:
145+ - name: deploy
146+ image: docker:24
147+ environment:
148+ GORDON_TOKEN:
149+ from_secret: gordon_token
150+ GORDON_REMOTE:
151+ from_secret: gordon_remote
152+ commands:
153+ - apk add --no-cache curl
154+ - curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64
155+ -o /usr/local/bin/gordon
156+ - chmod +x /usr/local/bin/gordon
157+ - gordon push --build --remote "$GORDON_REMOTE" --no-confirm
158+
159+trigger:
160+ event:
161+ - tag
162+```
163+
164+## Token Scopes Reference
165+
166+| Workflow | Required Scopes |
167+|----------|----------------|
168+| Build + push + deploy | `push,pull,admin:routes:read,admin:config:write` |
169+| Push only (no deploy) | `push,pull,admin:routes:read` |
170+| docker push (auto-deploy) | `push,pull` |
171+
172+## Troubleshooting
173+
174+### "failed to verify token"
175+
176+The token is invalid or has been revoked. Generate a new one.
177+
178+### "no route configured for image"
179+
180+The route must exist before pushing. Create it with:
181+
182+```bash
183+gordon routes add myapp.example.com myapp
184+# or for first deploy:
185+gordon bootstrap myapp.example.com myapp
186+```
187+
188+### Version shows "latest"
189+
190+Gordon could not detect a version tag. Either:
191+- Tag your git repo: `git tag v1.0.0 && git push --tags`
192+- Pass explicitly: `gordon push --tag v1.0.0`
193+
194+### Large images time out
195+
196+Gordon uploads in 50MB chunks. For very large images (> 1GB), the push may take several minutes. Ensure your CI runner timeout is sufficient.
197+
198+## Related
199+
200+- [GitHub Actions](./github-actions.md)
201+- [GitLab CI](./gitlab-ci.md)
202+- [Deployment Overview](./index.md)
203+- [Authentication](../config/auth.md)
204+- [Push Command](../cli/push.md)
@@ -0,0 +1,204 @@
1+# Generic CI/CD Deployment
2+
3+Deploy with Gordon from any CI/CD system.
4+
5+## Requirements
6+
7+- Docker available on CI runner (for building images)
8+- Network access to your Gordon server (HTTPS)
9+- Gordon binary (optional but recommended)
10+
11+## Recommended: gordon push
12+
13+### 1. Generate Deployment Token
14+
15+On your Gordon server:
16+
17+```bash
18+gordon auth token generate \
19+ --subject ci-deploy \
20+ --scopes "push,pull,admin:routes:read,admin:config:write" \
21+ --expiry 0
22+```
23+
24+### 2. Configure CI Secrets
25+
26+Add these secrets to your CI system:
27+
28+| Secret | Value |
29+|--------|-------|
30+| `GORDON_TOKEN` | The generated token |
31+| `GORDON_REMOTE` | `https://gordon.example.com` |
32+
33+### 3. Pipeline Steps
34+
35+```bash
36+# 1. Install Gordon binary
37+curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 \
38+ -o /usr/local/bin/gordon
39+chmod +x /usr/local/bin/gordon
40+
41+# 2. Build, push, and deploy
42+export GORDON_TOKEN="$GORDON_TOKEN"
43+gordon push --build \
44+ --remote "$GORDON_REMOTE" \
45+ --no-confirm
46+```
47+
48+Gordon auto-detects the version from CI environment variables:
49+
50+| CI System | Variable | Example |
51+|-----------|----------|---------|
52+| GitHub Actions | `$GITHUB_REF` | `refs/tags/v1.2.0` |
53+| GitLab CI | `$CI_COMMIT_TAG` | `v1.2.0` |
54+| Azure DevOps | `$BUILD_SOURCEBRANCH` | `refs/tags/v1.2.0` |
55+| Other | `--tag` flag | `gordon push --tag v1.2.0` |
56+
57+## Alternative: docker push
58+
59+If installing the Gordon binary is not possible:
60+
61+```bash
62+# 1. Login to Gordon registry
63+echo "$GORDON_TOKEN" | docker login gordon.example.com \
64+ -u ci-deploy --password-stdin
65+
66+# 2. Build and push
67+docker build -t gordon.example.com/myapp:v1.0.0 .
68+docker push gordon.example.com/myapp:v1.0.0
69+```
70+
71+This requires the token subject (`ci-deploy`) as the username.
72+Gordon auto-deploys when it receives the image.
73+
74+## CI System Examples
75+
76+### Jenkins
77+
78+```groovy
79+pipeline {
80+ agent any
81+ environment {
82+ GORDON_TOKEN = credentials('gordon-token')
83+ GORDON_REMOTE = 'https://gordon.example.com'
84+ }
85+ stages {
86+ stage('Deploy') {
87+ steps {
88+ sh '''
89+ curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 \
90+ -o /usr/local/bin/gordon
91+ chmod +x /usr/local/bin/gordon
92+ gordon push --build --remote "$GORDON_REMOTE" --no-confirm
93+ '''
94+ }
95+ }
96+ }
97+}
98+```
99+
100+### CircleCI
101+
102+```yaml
103+version: 2.1
104+
105+jobs:
106+ deploy:
107+ docker:
108+ - image: docker:24
109+ steps:
110+ - checkout
111+ - setup_remote_docker
112+ - run:
113+ name: Install Gordon
114+ command: |
115+ apk add --no-cache curl
116+ curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 \
117+ -o /usr/local/bin/gordon
118+ chmod +x /usr/local/bin/gordon
119+ - run:
120+ name: Deploy
121+ command: |
122+ gordon push --build \
123+ --remote "$GORDON_REMOTE" \
124+ --no-confirm
125+
126+workflows:
127+ deploy:
128+ jobs:
129+ - deploy:
130+ filters:
131+ tags:
132+ only: /^v.*/
133+ branches:
134+ ignore: /.*/
135+```
136+
137+### Drone
138+
139+```yaml
140+kind: pipeline
141+type: docker
142+name: deploy
143+
144+steps:
145+ - name: deploy
146+ image: docker:24
147+ environment:
148+ GORDON_TOKEN:
149+ from_secret: gordon_token
150+ GORDON_REMOTE:
151+ from_secret: gordon_remote
152+ commands:
153+ - apk add --no-cache curl
154+ - curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64
155+ -o /usr/local/bin/gordon
156+ - chmod +x /usr/local/bin/gordon
157+ - gordon push --build --remote "$GORDON_REMOTE" --no-confirm
158+
159+trigger:
160+ event:
161+ - tag
162+```
163+
164+## Token Scopes Reference
165+
166+| Workflow | Required Scopes |
167+|----------|----------------|
168+| Build + push + deploy | `push,pull,admin:routes:read,admin:config:write` |
169+| Push only (no deploy) | `push,pull,admin:routes:read` |
170+| docker push (auto-deploy) | `push,pull` |
171+
172+## Troubleshooting
173+
174+### "failed to verify token"
175+
176+The token is invalid or has been revoked. Generate a new one.
177+
178+### "no route configured for image"
179+
180+The route must exist before pushing. Create it with:
181+
182+```bash
183+gordon routes add myapp.example.com myapp
184+# or for first deploy:
185+gordon bootstrap myapp.example.com myapp
186+```
187+
188+### Version shows "latest"
189+
190+Gordon could not detect a version tag. Either:
191+- Tag your git repo: `git tag v1.0.0 && git push --tags`
192+- Pass explicitly: `gordon push --tag v1.0.0`
193+
194+### Large images time out
195+
196+Gordon uploads in 50MB chunks. For very large images (> 1GB), the push may take several minutes. Ensure your CI runner timeout is sufficient.
197+
198+## Related
199+
200+- [GitHub Actions](./github-actions.md)
201+- [GitLab CI](./gitlab-ci.md)
202+- [Deployment Overview](./index.md)
203+- [Authentication](../config/auth.md)
204+- [Push Command](../cli/push.md)
M docs/deployment/github-actions.md +252 -55
@@ -1,21 +1,26 @@
11 # GitHub Actions Deployment
22
3-Automated deployment with GitHub Actions using Gordon's official action.
3+Two approaches for deploying with GitHub Actions: the `gordon push` CLI (recommended) or a Docker-based workflow using Gordon's official action.
44
55 ## Prerequisites
66
77 1. Gordon server running with registry authentication enabled
8-2. Generated deployment token
8+2. Deployment token generated with the required scopes
99 3. GitHub repository secrets configured
1010
11-## Quick Setup
11+## Recommended: gordon push
1212
13-### 1. Generate Deployment Token
13+Use the `gordon push` CLI for a lightweight, single-step build and deploy.
14+
15+### 1. Generate Token
1416
1517 On your Gordon server:
1618
1719 ```bash
18-gordon auth token generate --subject github-actions --scopes push,pull --expiry 0
20+gordon auth token generate \
21+ --subject github-actions \
22+ --scopes "push,pull,admin:routes:read,admin:config:write" \
23+ --expiry 0
1924 ```
2025
2126 Save the token output.
@@ -26,70 +31,235 @@ In your repository: Settings → Secrets → Actions → New repository secret
2631
2732 | Secret | Value |
2833 |--------|-------|
29-| `GORDON_REGISTRY` | `registry.mydomain.com` |
30-| `GORDON_USERNAME` | `github-actions` |
3134 | `GORDON_TOKEN` | The generated token |
35+| `GORDON_REMOTE` | `https://gordon.example.com` |
36+
37+### 3. Install Gordon Binary
38+
39+Add this step to your workflow to download the Gordon binary:
40+
41+```yaml
42+- name: Install Gordon
43+ run: |
44+ curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
45+ chmod +x /usr/local/bin/gordon
46+```
47+
48+### 4. Workflow Examples
3249
33-### 3. Create Workflow
50+#### Deploy on Tag Push
3451
35-Create `.github/workflows/deploy.yml`:
52+Gordon auto-detects the version from `$GITHUB_REF` (e.g., `refs/tags/v1.2.0` → `v1.2.0`).
3653
3754 ```yaml
3855 name: Deploy to Gordon
3956
4057 on:
4158 push:
42- tags:
43- - 'v*'
59+ tags: ['v*']
4460
4561 jobs:
4662 deploy:
4763 runs-on: ubuntu-latest
4864 steps:
49- - uses: actions/checkout@v6
65+ - uses: actions/checkout@v4
66+
67+ - name: Install Gordon
68+ run: |
69+ curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
70+ chmod +x /usr/local/bin/gordon
71+
72+ - name: Build and Deploy
73+ env:
74+ GORDON_TOKEN: ${{ secrets.GORDON_TOKEN }}
75+ run: |
76+ gordon push --build \
77+ --remote ${{ secrets.GORDON_REMOTE }} \
78+ --no-confirm
79+```
5080
51- - name: Deploy to Gordon
52- uses: bnema/gordon/.github/actions/deploy@main
81+#### Continuous Deploy on Main
82+
83+Deploy on every push to main. The version defaults to `latest` or the output of `git describe`.
84+
85+```yaml
86+name: Deploy to Gordon
87+
88+on:
89+ push:
90+ branches:
91+ - main
92+
93+jobs:
94+ deploy:
95+ runs-on: ubuntu-latest
96+ steps:
97+ - uses: actions/checkout@v4
5398 with:
54- registry: ${{ secrets.GORDON_REGISTRY }}
55- username: ${{ secrets.GORDON_USERNAME }}
56- password: ${{ secrets.GORDON_TOKEN }}
99+ fetch-depth: 0
100+
101+ - name: Install Gordon
102+ run: |
103+ curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
104+ chmod +x /usr/local/bin/gordon
105+
106+ - name: Build and Deploy
107+ env:
108+ GORDON_TOKEN: ${{ secrets.GORDON_TOKEN }}
109+ run: |
110+ gordon push --build \
111+ --remote ${{ secrets.GORDON_REMOTE }} \
112+ --tag latest \
113+ --no-confirm
57114 ```
58115
59-### 4. Deploy
116+#### Manual Dispatch
60117
61-```bash
62-git tag v1.0.0
63-git push origin v1.0.0
118+Allow manual deployments with an optional tag input:
119+
120+```yaml
121+name: Deploy to Gordon
122+
123+on:
124+ workflow_dispatch:
125+ inputs:
126+ tag:
127+ description: 'Tag to deploy (leave empty to use git describe)'
128+ required: false
129+
130+jobs:
131+ deploy:
132+ runs-on: ubuntu-latest
133+ steps:
134+ - uses: actions/checkout@v4
135+ with:
136+ ref: ${{ github.event.inputs.tag || github.ref }}
137+ fetch-depth: 0
138+
139+ - name: Install Gordon
140+ run: |
141+ curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
142+ chmod +x /usr/local/bin/gordon
143+
144+ - name: Build and Deploy
145+ env:
146+ GORDON_TOKEN: ${{ secrets.GORDON_TOKEN }}
147+ run: |
148+ gordon push --build \
149+ --remote ${{ secrets.GORDON_REMOTE }} \
150+ ${{ github.event.inputs.tag && format('--tag {0}', github.event.inputs.tag) || '' }} \
151+ --no-confirm
64152 ```
65153
66-## Action Reference
154+#### Monorepo
67155
68-### Inputs
156+Deploy multiple services with separate `gordon push` calls:
69157
70-| Input | Required | Default | Description |
71-|-------|----------|---------|-------------|
72-| `registry` | Yes | - | Gordon registry URL |
73-| `username` | Yes | - | Registry username |
74-| `password` | Yes | - | Registry token |
75-| `image` | No | repo name | Image name |
76-| `tag` | No | git tag/SHA | Image tag |
77-| `dockerfile` | No | `./Dockerfile` | Dockerfile path |
78-| `context` | No | `.` | Build context |
79-| `push-latest` | No | `false` | Also push :latest tag |
80-| `platforms` | No | `linux/amd64` | Target platforms |
81-| `build-args` | No | - | Build arguments |
158+```yaml
159+name: Deploy Services
82160
83-### Outputs
161+on:
162+ push:
163+ tags: ['v*']
84164
85-| Output | Description |
86-|--------|-------------|
87-| `image` | Full image name |
88-| `tag` | Image tag |
165+jobs:
166+ deploy:
167+ runs-on: ubuntu-latest
168+ steps:
169+ - uses: actions/checkout@v4
170+
171+ - name: Install Gordon
172+ run: |
173+ curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
174+ chmod +x /usr/local/bin/gordon
175+
176+ - name: Deploy API
177+ env:
178+ GORDON_TOKEN: ${{ secrets.GORDON_TOKEN }}
179+ run: |
180+ gordon push --build \
181+ --remote ${{ secrets.GORDON_REMOTE }} \
182+ --file ./services/api/Dockerfile \
183+ myapp-api \
184+ --no-confirm
185+
186+ - name: Deploy Web
187+ env:
188+ GORDON_TOKEN: ${{ secrets.GORDON_TOKEN }}
189+ run: |
190+ gordon push --build \
191+ --remote ${{ secrets.GORDON_REMOTE }} \
192+ --file ./services/web/Dockerfile \
193+ myapp-web \
194+ --no-confirm
195+```
89196
90-## Workflow Examples
197+#### With Build Args
91198
92-### Deploy on Tag Push
199+Pass build arguments to the Docker build:
200+
201+```yaml
202+- name: Build and Deploy
203+ env:
204+ GORDON_TOKEN: ${{ secrets.GORDON_TOKEN }}
205+ run: |
206+ gordon push --build \
207+ --remote ${{ secrets.GORDON_REMOTE }} \
208+ --build-arg NODE_ENV=production \
209+ --build-arg API_URL=https://api.example.com \
210+ --build-arg BUILD_DATE=${{ github.event.head_commit.timestamp }} \
211+ --no-confirm
212+```
213+
214+## Alternative: Docker-based Workflow
215+
216+For environments where installing the Gordon binary is not desired, use Docker directly to build and push to the Gordon registry. Gordon auto-deploys when it receives the image — no explicit deploy step is needed.
217+
218+### Setup
219+
220+Add these secrets to your repository:
221+
222+| Secret | Value |
223+|--------|-------|
224+| `GORDON_REGISTRY` | `registry.gordon.example.com` |
225+| `GORDON_USERNAME` | `github-actions` |
226+| `GORDON_TOKEN` | The generated token |
227+
228+### Workflow
229+
230+```yaml
231+name: Deploy to Gordon
232+
233+on:
234+ push:
235+ tags: ['v*']
236+
237+jobs:
238+ deploy:
239+ runs-on: ubuntu-latest
240+ steps:
241+ - uses: actions/checkout@v4
242+
243+ - name: Login to Gordon Registry
244+ run: echo "${{ secrets.GORDON_TOKEN }}" | docker login ${{ secrets.GORDON_REGISTRY }} -u ${{ secrets.GORDON_USERNAME }} --password-stdin
245+
246+ - name: Build and Push
247+ run: |
248+ docker build -t ${{ secrets.GORDON_REGISTRY }}/myapp:${{ github.ref_name }} .
249+ docker push ${{ secrets.GORDON_REGISTRY }}/myapp:${{ github.ref_name }}
250+```
251+
252+## Alternative: Gordon GitHub Action
253+
254+Use the official `bnema/gordon` action for a fully declarative workflow. This action handles login, build, and push in a single step.
255+
256+### Setup
257+
258+Requires the same 3 secrets as the Docker-based workflow: `GORDON_REGISTRY`, `GORDON_USERNAME`, `GORDON_TOKEN`.
259+
260+### Workflow Examples
261+
262+#### Deploy on Tag Push
93263
94264 ```yaml
95265 name: Deploy to Gordon
@@ -103,7 +273,7 @@ jobs:
103273 deploy:
104274 runs-on: ubuntu-latest
105275 steps:
106- - uses: actions/checkout@v6
276+ - uses: actions/checkout@v4
107277
108278 - name: Deploy to Gordon
109279 uses: bnema/gordon/.github/actions/deploy@main
@@ -113,7 +283,7 @@ jobs:
113283 password: ${{ secrets.GORDON_TOKEN }}
114284 ```
115285
116-### Continuous Deployment
286+#### Continuous Deployment
117287
118288 Deploy on every push to main:
119289
@@ -129,7 +299,7 @@ jobs:
129299 deploy:
130300 runs-on: ubuntu-latest
131301 steps:
132- - uses: actions/checkout@v6
302+ - uses: actions/checkout@v4
133303
134304 - name: Deploy to Gordon
135305 uses: bnema/gordon/.github/actions/deploy@main
@@ -140,9 +310,9 @@ jobs:
140310 push-latest: 'true'
141311 ```
142312
143-### Manual Deployment
313+#### Manual Deployment
144314
145-Allow manual deployments with custom tag:
315+Allow manual deployments with a custom tag:
146316
147317 ```yaml
148318 name: Deploy to Gordon
@@ -158,7 +328,7 @@ jobs:
158328 deploy:
159329 runs-on: ubuntu-latest
160330 steps:
161- - uses: actions/checkout@v6
331+ - uses: actions/checkout@v4
162332 with:
163333 ref: ${{ github.event.inputs.tag || github.ref }}
164334
@@ -171,7 +341,7 @@ jobs:
171341 tag: ${{ github.event.inputs.tag }}
172342 ```
173343
174-### Monorepo Deployment
344+#### Monorepo Deployment
175345
176346 Deploy multiple services:
177347
@@ -187,7 +357,7 @@ jobs:
187357 deploy-api:
188358 runs-on: ubuntu-latest
189359 steps:
190- - uses: actions/checkout@v6
360+ - uses: actions/checkout@v4
191361 - uses: bnema/gordon/.github/actions/deploy@main
192362 with:
193363 registry: ${{ secrets.GORDON_REGISTRY }}
@@ -200,7 +370,7 @@ jobs:
200370 deploy-web:
201371 runs-on: ubuntu-latest
202372 steps:
203- - uses: actions/checkout@v6
373+ - uses: actions/checkout@v4
204374 - uses: bnema/gordon/.github/actions/deploy@main
205375 with:
206376 registry: ${{ secrets.GORDON_REGISTRY }}
@@ -211,7 +381,7 @@ jobs:
211381 context: ./services/web
212382 ```
213383
214-### With Build Arguments
384+#### With Build Arguments
215385
216386 ```yaml
217387 - uses: bnema/gordon/.github/actions/deploy@main
@@ -225,7 +395,7 @@ jobs:
225395 BUILD_DATE=${{ github.event.head_commit.timestamp }}
226396 ```
227397
228-### Multi-Platform Build
398+#### Multi-Platform Build
229399
230400 ```yaml
231401 - uses: bnema/gordon/.github/actions/deploy@main
@@ -236,7 +406,31 @@ jobs:
236406 platforms: linux/amd64,linux/arm64
237407 ```
238408
239-## Deployment Summary
409+### Action Reference
410+
411+#### Inputs
412+
413+| Input | Required | Default | Description |
414+|-------|----------|---------|-------------|
415+| `registry` | Yes | - | Gordon registry URL |
416+| `username` | Yes | - | Registry username |
417+| `password` | Yes | - | Registry token |
418+| `image` | No | repo name | Image name |
419+| `tag` | No | git tag/SHA | Image tag |
420+| `dockerfile` | No | `./Dockerfile` | Dockerfile path |
421+| `context` | No | `.` | Build context |
422+| `push-latest` | No | `false` | Also push :latest tag |
423+| `platforms` | No | `linux/amd64` | Target platforms |
424+| `build-args` | No | - | Build arguments |
425+
426+#### Outputs
427+
428+| Output | Description |
429+|--------|-------------|
430+| `image` | Full image name |
431+| `tag` | Image tag |
432+
433+#### Deployment Summary
240434
241435 Add a deployment summary to your workflow:
242436
@@ -277,6 +471,9 @@ Error: unauthorized: authentication required
277471
278472 ## Related
279473
280-- [Authentication](../config/auth.md)
474+- [GitLab CI](./gitlab-ci.md)
475+- [Generic CI](./generic-ci.md)
281476 - [Deployment Overview](./index.md)
477+- [Authentication](../config/auth.md)
478+- [Push Command](../cli/push.md)
282479 - [Rollback](./rollback.md)
@@ -1,21 +1,26 @@
1 # GitHub Actions Deployment1 # GitHub Actions Deployment
2 2
3-Automated deployment with GitHub Actions using Gordon's official action.3+Two approaches for deploying with GitHub Actions: the `gordon push` CLI (recommended) or a Docker-based workflow using Gordon's official action.
4 4
5 ## Prerequisites5 ## Prerequisites
6 6
7 1. Gordon server running with registry authentication enabled7 1. Gordon server running with registry authentication enabled
8-2. Generated deployment token8+2. Deployment token generated with the required scopes
9 3. GitHub repository secrets configured9 3. GitHub repository secrets configured
10 10
11-## Quick Setup11+## Recommended: gordon push
12 12
13-### 1. Generate Deployment Token13+Use the `gordon push` CLI for a lightweight, single-step build and deploy.
14+
15+### 1. Generate Token
14 16
15 On your Gordon server:17 On your Gordon server:
16 18
17 ```bash19 ```bash
18-gordon auth token generate --subject github-actions --scopes push,pull --expiry 020+gordon auth token generate \
21+ --subject github-actions \
22+ --scopes "push,pull,admin:routes:read,admin:config:write" \
23+ --expiry 0
19 ```24 ```
20 25
21 Save the token output.26 Save the token output.
@@ -26,70 +31,235 @@ In your repository: Settings → Secrets → Actions → New repository secret
26 31
27 | Secret | Value |32 | Secret | Value |
28 |--------|-------|33 |--------|-------|
29-| `GORDON_REGISTRY` | `registry.mydomain.com` |
30-| `GORDON_USERNAME` | `github-actions` |
31 | `GORDON_TOKEN` | The generated token |34 | `GORDON_TOKEN` | The generated token |
35+| `GORDON_REMOTE` | `https://gordon.example.com` |
36+
37+### 3. Install Gordon Binary
38+
39+Add this step to your workflow to download the Gordon binary:
40+
41+```yaml
42+- name: Install Gordon
43+ run: |
44+ curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
45+ chmod +x /usr/local/bin/gordon
46+```
47+
48+### 4. Workflow Examples
32 49
33-### 3. Create Workflow50+#### Deploy on Tag Push
34 51
35-Create `.github/workflows/deploy.yml`:52+Gordon auto-detects the version from `$GITHUB_REF` (e.g., `refs/tags/v1.2.0` → `v1.2.0`).
36 53
37 ```yaml54 ```yaml
38 name: Deploy to Gordon55 name: Deploy to Gordon
39 56
40 on:57 on:
41 push:58 push:
42- tags:59+ tags: ['v*']
43- - 'v*'
44 60
45 jobs:61 jobs:
46 deploy:62 deploy:
47 runs-on: ubuntu-latest63 runs-on: ubuntu-latest
48 steps:64 steps:
49- - uses: actions/checkout@v665+ - uses: actions/checkout@v4
66+
67+ - name: Install Gordon
68+ run: |
69+ curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
70+ chmod +x /usr/local/bin/gordon
71+
72+ - name: Build and Deploy
73+ env:
74+ GORDON_TOKEN: ${{ secrets.GORDON_TOKEN }}
75+ run: |
76+ gordon push --build \
77+ --remote ${{ secrets.GORDON_REMOTE }} \
78+ --no-confirm
79+```
50 80
51- - name: Deploy to Gordon81+#### Continuous Deploy on Main
52- uses: bnema/gordon/.github/actions/deploy@main82+
83+Deploy on every push to main. The version defaults to `latest` or the output of `git describe`.
84+
85+```yaml
86+name: Deploy to Gordon
87+
88+on:
89+ push:
90+ branches:
91+ - main
92+
93+jobs:
94+ deploy:
95+ runs-on: ubuntu-latest
96+ steps:
97+ - uses: actions/checkout@v4
53 with:98 with:
54- registry: ${{ secrets.GORDON_REGISTRY }}99+ fetch-depth: 0
55- username: ${{ secrets.GORDON_USERNAME }}100+
56- password: ${{ secrets.GORDON_TOKEN }}101+ - name: Install Gordon
102+ run: |
103+ curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
104+ chmod +x /usr/local/bin/gordon
105+
106+ - name: Build and Deploy
107+ env:
108+ GORDON_TOKEN: ${{ secrets.GORDON_TOKEN }}
109+ run: |
110+ gordon push --build \
111+ --remote ${{ secrets.GORDON_REMOTE }} \
112+ --tag latest \
113+ --no-confirm
57 ```114 ```
58 115
59-### 4. Deploy116+#### Manual Dispatch
60 117
61-```bash118+Allow manual deployments with an optional tag input:
62-git tag v1.0.0119+
63-git push origin v1.0.0120+```yaml
121+name: Deploy to Gordon
122+
123+on:
124+ workflow_dispatch:
125+ inputs:
126+ tag:
127+ description: 'Tag to deploy (leave empty to use git describe)'
128+ required: false
129+
130+jobs:
131+ deploy:
132+ runs-on: ubuntu-latest
133+ steps:
134+ - uses: actions/checkout@v4
135+ with:
136+ ref: ${{ github.event.inputs.tag || github.ref }}
137+ fetch-depth: 0
138+
139+ - name: Install Gordon
140+ run: |
141+ curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
142+ chmod +x /usr/local/bin/gordon
143+
144+ - name: Build and Deploy
145+ env:
146+ GORDON_TOKEN: ${{ secrets.GORDON_TOKEN }}
147+ run: |
148+ gordon push --build \
149+ --remote ${{ secrets.GORDON_REMOTE }} \
150+ ${{ github.event.inputs.tag && format('--tag {0}', github.event.inputs.tag) || '' }} \
151+ --no-confirm
64 ```152 ```
65 153
66-## Action Reference154+#### Monorepo
67 155
68-### Inputs156+Deploy multiple services with separate `gordon push` calls:
69 157
70-| Input | Required | Default | Description |158+```yaml
71-|-------|----------|---------|-------------|159+name: Deploy Services
72-| `registry` | Yes | - | Gordon registry URL |
73-| `username` | Yes | - | Registry username |
74-| `password` | Yes | - | Registry token |
75-| `image` | No | repo name | Image name |
76-| `tag` | No | git tag/SHA | Image tag |
77-| `dockerfile` | No | `./Dockerfile` | Dockerfile path |
78-| `context` | No | `.` | Build context |
79-| `push-latest` | No | `false` | Also push :latest tag |
80-| `platforms` | No | `linux/amd64` | Target platforms |
81-| `build-args` | No | - | Build arguments |
82 160
83-### Outputs161+on:
162+ push:
163+ tags: ['v*']
84 164
85-| Output | Description |165+jobs:
86-|--------|-------------|166+ deploy:
87-| `image` | Full image name |167+ runs-on: ubuntu-latest
88-| `tag` | Image tag |168+ steps:
169+ - uses: actions/checkout@v4
170+
171+ - name: Install Gordon
172+ run: |
173+ curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
174+ chmod +x /usr/local/bin/gordon
175+
176+ - name: Deploy API
177+ env:
178+ GORDON_TOKEN: ${{ secrets.GORDON_TOKEN }}
179+ run: |
180+ gordon push --build \
181+ --remote ${{ secrets.GORDON_REMOTE }} \
182+ --file ./services/api/Dockerfile \
183+ myapp-api \
184+ --no-confirm
185+
186+ - name: Deploy Web
187+ env:
188+ GORDON_TOKEN: ${{ secrets.GORDON_TOKEN }}
189+ run: |
190+ gordon push --build \
191+ --remote ${{ secrets.GORDON_REMOTE }} \
192+ --file ./services/web/Dockerfile \
193+ myapp-web \
194+ --no-confirm
195+```
89 196
90-## Workflow Examples197+#### With Build Args
91 198
92-### Deploy on Tag Push199+Pass build arguments to the Docker build:
200+
201+```yaml
202+- name: Build and Deploy
203+ env:
204+ GORDON_TOKEN: ${{ secrets.GORDON_TOKEN }}
205+ run: |
206+ gordon push --build \
207+ --remote ${{ secrets.GORDON_REMOTE }} \
208+ --build-arg NODE_ENV=production \
209+ --build-arg API_URL=https://api.example.com \
210+ --build-arg BUILD_DATE=${{ github.event.head_commit.timestamp }} \
211+ --no-confirm
212+```
213+
214+## Alternative: Docker-based Workflow
215+
216+For environments where installing the Gordon binary is not desired, use Docker directly to build and push to the Gordon registry. Gordon auto-deploys when it receives the image — no explicit deploy step is needed.
217+
218+### Setup
219+
220+Add these secrets to your repository:
221+
222+| Secret | Value |
223+|--------|-------|
224+| `GORDON_REGISTRY` | `registry.gordon.example.com` |
225+| `GORDON_USERNAME` | `github-actions` |
226+| `GORDON_TOKEN` | The generated token |
227+
228+### Workflow
229+
230+```yaml
231+name: Deploy to Gordon
232+
233+on:
234+ push:
235+ tags: ['v*']
236+
237+jobs:
238+ deploy:
239+ runs-on: ubuntu-latest
240+ steps:
241+ - uses: actions/checkout@v4
242+
243+ - name: Login to Gordon Registry
244+ run: echo "${{ secrets.GORDON_TOKEN }}" | docker login ${{ secrets.GORDON_REGISTRY }} -u ${{ secrets.GORDON_USERNAME }} --password-stdin
245+
246+ - name: Build and Push
247+ run: |
248+ docker build -t ${{ secrets.GORDON_REGISTRY }}/myapp:${{ github.ref_name }} .
249+ docker push ${{ secrets.GORDON_REGISTRY }}/myapp:${{ github.ref_name }}
250+```
251+
252+## Alternative: Gordon GitHub Action
253+
254+Use the official `bnema/gordon` action for a fully declarative workflow. This action handles login, build, and push in a single step.
255+
256+### Setup
257+
258+Requires the same 3 secrets as the Docker-based workflow: `GORDON_REGISTRY`, `GORDON_USERNAME`, `GORDON_TOKEN`.
259+
260+### Workflow Examples
261+
262+#### Deploy on Tag Push
93 263
94 ```yaml264 ```yaml
95 name: Deploy to Gordon265 name: Deploy to Gordon
@@ -103,7 +273,7 @@ jobs:
103 deploy:273 deploy:
104 runs-on: ubuntu-latest274 runs-on: ubuntu-latest
105 steps:275 steps:
106- - uses: actions/checkout@v6276+ - uses: actions/checkout@v4
107 277
108 - name: Deploy to Gordon278 - name: Deploy to Gordon
109 uses: bnema/gordon/.github/actions/deploy@main279 uses: bnema/gordon/.github/actions/deploy@main
@@ -113,7 +283,7 @@ jobs:
113 password: ${{ secrets.GORDON_TOKEN }}283 password: ${{ secrets.GORDON_TOKEN }}
114 ```284 ```
115 285
116-### Continuous Deployment286+#### Continuous Deployment
117 287
118 Deploy on every push to main:288 Deploy on every push to main:
119 289
@@ -129,7 +299,7 @@ jobs:
129 deploy:299 deploy:
130 runs-on: ubuntu-latest300 runs-on: ubuntu-latest
131 steps:301 steps:
132- - uses: actions/checkout@v6302+ - uses: actions/checkout@v4
133 303
134 - name: Deploy to Gordon304 - name: Deploy to Gordon
135 uses: bnema/gordon/.github/actions/deploy@main305 uses: bnema/gordon/.github/actions/deploy@main
@@ -140,9 +310,9 @@ jobs:
140 push-latest: 'true'310 push-latest: 'true'
141 ```311 ```
142 312
143-### Manual Deployment313+#### Manual Deployment
144 314
145-Allow manual deployments with custom tag:315+Allow manual deployments with a custom tag:
146 316
147 ```yaml317 ```yaml
148 name: Deploy to Gordon318 name: Deploy to Gordon
@@ -158,7 +328,7 @@ jobs:
158 deploy:328 deploy:
159 runs-on: ubuntu-latest329 runs-on: ubuntu-latest
160 steps:330 steps:
161- - uses: actions/checkout@v6331+ - uses: actions/checkout@v4
162 with:332 with:
163 ref: ${{ github.event.inputs.tag || github.ref }}333 ref: ${{ github.event.inputs.tag || github.ref }}
164 334
@@ -171,7 +341,7 @@ jobs:
171 tag: ${{ github.event.inputs.tag }}341 tag: ${{ github.event.inputs.tag }}
172 ```342 ```
173 343
174-### Monorepo Deployment344+#### Monorepo Deployment
175 345
176 Deploy multiple services:346 Deploy multiple services:
177 347
@@ -187,7 +357,7 @@ jobs:
187 deploy-api:357 deploy-api:
188 runs-on: ubuntu-latest358 runs-on: ubuntu-latest
189 steps:359 steps:
190- - uses: actions/checkout@v6360+ - uses: actions/checkout@v4
191 - uses: bnema/gordon/.github/actions/deploy@main361 - uses: bnema/gordon/.github/actions/deploy@main
192 with:362 with:
193 registry: ${{ secrets.GORDON_REGISTRY }}363 registry: ${{ secrets.GORDON_REGISTRY }}
@@ -200,7 +370,7 @@ jobs:
200 deploy-web:370 deploy-web:
201 runs-on: ubuntu-latest371 runs-on: ubuntu-latest
202 steps:372 steps:
203- - uses: actions/checkout@v6373+ - uses: actions/checkout@v4
204 - uses: bnema/gordon/.github/actions/deploy@main374 - uses: bnema/gordon/.github/actions/deploy@main
205 with:375 with:
206 registry: ${{ secrets.GORDON_REGISTRY }}376 registry: ${{ secrets.GORDON_REGISTRY }}
@@ -211,7 +381,7 @@ jobs:
211 context: ./services/web381 context: ./services/web
212 ```382 ```
213 383
214-### With Build Arguments384+#### With Build Arguments
215 385
216 ```yaml386 ```yaml
217 - uses: bnema/gordon/.github/actions/deploy@main387 - uses: bnema/gordon/.github/actions/deploy@main
@@ -225,7 +395,7 @@ jobs:
225 BUILD_DATE=${{ github.event.head_commit.timestamp }}395 BUILD_DATE=${{ github.event.head_commit.timestamp }}
226 ```396 ```
227 397
228-### Multi-Platform Build398+#### Multi-Platform Build
229 399
230 ```yaml400 ```yaml
231 - uses: bnema/gordon/.github/actions/deploy@main401 - uses: bnema/gordon/.github/actions/deploy@main
@@ -236,7 +406,31 @@ jobs:
236 platforms: linux/amd64,linux/arm64406 platforms: linux/amd64,linux/arm64
237 ```407 ```
238 408
239-## Deployment Summary409+### Action Reference
410+
411+#### Inputs
412+
413+| Input | Required | Default | Description |
414+|-------|----------|---------|-------------|
415+| `registry` | Yes | - | Gordon registry URL |
416+| `username` | Yes | - | Registry username |
417+| `password` | Yes | - | Registry token |
418+| `image` | No | repo name | Image name |
419+| `tag` | No | git tag/SHA | Image tag |
420+| `dockerfile` | No | `./Dockerfile` | Dockerfile path |
421+| `context` | No | `.` | Build context |
422+| `push-latest` | No | `false` | Also push :latest tag |
423+| `platforms` | No | `linux/amd64` | Target platforms |
424+| `build-args` | No | - | Build arguments |
425+
426+#### Outputs
427+
428+| Output | Description |
429+|--------|-------------|
430+| `image` | Full image name |
431+| `tag` | Image tag |
432+
433+#### Deployment Summary
240 434
241 Add a deployment summary to your workflow:435 Add a deployment summary to your workflow:
242 436
@@ -277,6 +471,9 @@ Error: unauthorized: authentication required
277 471
278 ## Related472 ## Related
279 473
280-- [Authentication](../config/auth.md)474+- [GitLab CI](./gitlab-ci.md)
475+- [Generic CI](./generic-ci.md)
281 - [Deployment Overview](./index.md)476 - [Deployment Overview](./index.md)
477+- [Authentication](../config/auth.md)
478+- [Push Command](../cli/push.md)
282 - [Rollback](./rollback.md)479 - [Rollback](./rollback.md)
A docs/deployment/gitlab-ci.md +211 -0
@@ -0,0 +1,211 @@
1+# GitLab CI/CD Deployment
2+
3+Automated deployment with GitLab CI/CD using Gordon's push command.
4+
5+## Prerequisites
6+
7+1. Gordon server running with registry authentication enabled
8+2. Generated deployment token
9+3. GitLab CI/CD variables configured
10+
11+## Quick Setup
12+
13+### 1. Generate Deployment Token
14+
15+On your Gordon server:
16+
17+```bash
18+gordon auth token generate \
19+ --subject gitlab-ci \
20+ --scopes "push,pull,admin:routes:read,admin:config:write" \
21+ --expiry 0
22+```
23+
24+### 2. Add CI/CD Variables
25+
26+In your project: Settings > CI/CD > Variables
27+
28+| Variable | Value | Protected | Masked |
29+|----------|-------|-----------|--------|
30+| `GORDON_TOKEN` | The generated token | Yes | Yes |
31+| `GORDON_REMOTE` | `https://gordon.example.com` | Yes | No |
32+
33+### 3. Create Pipeline
34+
35+Create `.gitlab-ci.yml`:
36+
37+```yaml
38+deploy:
39+ stage: deploy
40+ image: docker:24
41+ services:
42+ - docker:24-dind
43+ before_script:
44+ - apk add --no-cache curl
45+ - curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
46+ - chmod +x /usr/local/bin/gordon
47+ script:
48+ - gordon push --build
49+ --remote "$GORDON_REMOTE"
50+ --token "$GORDON_TOKEN"
51+ --no-confirm
52+ only:
53+ - tags
54+```
55+
56+Gordon auto-detects the version from `$CI_COMMIT_TAG`.
57+
58+## Pipeline Examples
59+
60+### Deploy on Tag Push
61+
62+```yaml
63+stages:
64+ - deploy
65+
66+deploy:
67+ stage: deploy
68+ image: docker:24
69+ services:
70+ - docker:24-dind
71+ before_script:
72+ - apk add --no-cache curl
73+ - curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
74+ - chmod +x /usr/local/bin/gordon
75+ script:
76+ - gordon push --build
77+ --remote "$GORDON_REMOTE"
78+ --token "$GORDON_TOKEN"
79+ --no-confirm
80+ rules:
81+ - if: $CI_COMMIT_TAG
82+```
83+
84+### Continuous Deployment
85+
86+Deploy on every push to main:
87+
88+```yaml
89+deploy:
90+ stage: deploy
91+ image: docker:24
92+ services:
93+ - docker:24-dind
94+ before_script:
95+ - apk add --no-cache curl
96+ - curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
97+ - chmod +x /usr/local/bin/gordon
98+ script:
99+ - gordon push --build
100+ --remote "$GORDON_REMOTE"
101+ --token "$GORDON_TOKEN"
102+ --no-confirm
103+ rules:
104+ - if: $CI_COMMIT_BRANCH == "main"
105+```
106+
107+### Manual Deployment
108+
109+```yaml
110+deploy:
111+ stage: deploy
112+ image: docker:24
113+ services:
114+ - docker:24-dind
115+ before_script:
116+ - apk add --no-cache curl
117+ - curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
118+ - chmod +x /usr/local/bin/gordon
119+ script:
120+ - gordon push --build
121+ --remote "$GORDON_REMOTE"
122+ --token "$GORDON_TOKEN"
123+ --no-confirm
124+ when: manual
125+```
126+
127+### With Build Arguments
128+
129+```yaml
130+deploy:
131+ stage: deploy
132+ image: docker:24
133+ services:
134+ - docker:24-dind
135+ before_script:
136+ - apk add --no-cache curl
137+ - curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
138+ - chmod +x /usr/local/bin/gordon
139+ script:
140+ - gordon push --build
141+ --remote "$GORDON_REMOTE"
142+ --token "$GORDON_TOKEN"
143+ --build-arg NODE_ENV=production
144+ --build-arg API_URL=https://api.example.com
145+ --no-confirm
146+ rules:
147+ - if: $CI_COMMIT_TAG
148+```
149+
150+## Alternative: Docker-based Pipeline
151+
152+For environments where installing the Gordon binary is not desired:
153+
154+```yaml
155+deploy:
156+ stage: deploy
157+ image: docker:24
158+ services:
159+ - docker:24-dind
160+ script:
161+ - echo "$GORDON_TOKEN" | docker login "$GORDON_REGISTRY" -u "$GORDON_USERNAME" --password-stdin
162+ - docker build -t "$GORDON_REGISTRY/myapp:$CI_COMMIT_TAG" .
163+ - docker push "$GORDON_REGISTRY/myapp:$CI_COMMIT_TAG"
164+ rules:
165+ - if: $CI_COMMIT_TAG
166+```
167+
168+This requires additional CI/CD variables: `GORDON_REGISTRY` and `GORDON_USERNAME`.
169+Gordon auto-deploys when it receives the image.
170+
171+## Version Detection
172+
173+Gordon automatically detects the version tag from GitLab CI environment variables:
174+
175+| Variable | Example | Result |
176+|----------|---------|--------|
177+| `$CI_COMMIT_TAG` | `v1.2.0` | Tag `v1.2.0` |
178+| No tag | - | Falls back to `git describe` or `latest` |
179+
180+## Troubleshooting
181+
182+### Authentication Failed
183+
184+```
185+Error: failed to verify token
186+```
187+
188+Verify `GORDON_TOKEN` is correctly set and the token has not been revoked.
189+
190+### Docker-in-Docker Issues
191+
192+If using `docker:dind`, ensure the service is properly configured:
193+
194+```yaml
195+services:
196+ - docker:24-dind
197+variables:
198+ DOCKER_TLS_CERTDIR: "/certs"
199+```
200+
201+### Build Context
202+
203+GitLab CI clones your repository automatically. The build context defaults to the repository root.
204+
205+## Related
206+
207+- [GitHub Actions](./github-actions.md)
208+- [Generic CI](./generic-ci.md)
209+- [Deployment Overview](./index.md)
210+- [Authentication](../config/auth.md)
211+- [Push Command](../cli/push.md)
@@ -0,0 +1,211 @@
1+# GitLab CI/CD Deployment
2+
3+Automated deployment with GitLab CI/CD using Gordon's push command.
4+
5+## Prerequisites
6+
7+1. Gordon server running with registry authentication enabled
8+2. Generated deployment token
9+3. GitLab CI/CD variables configured
10+
11+## Quick Setup
12+
13+### 1. Generate Deployment Token
14+
15+On your Gordon server:
16+
17+```bash
18+gordon auth token generate \
19+ --subject gitlab-ci \
20+ --scopes "push,pull,admin:routes:read,admin:config:write" \
21+ --expiry 0
22+```
23+
24+### 2. Add CI/CD Variables
25+
26+In your project: Settings > CI/CD > Variables
27+
28+| Variable | Value | Protected | Masked |
29+|----------|-------|-----------|--------|
30+| `GORDON_TOKEN` | The generated token | Yes | Yes |
31+| `GORDON_REMOTE` | `https://gordon.example.com` | Yes | No |
32+
33+### 3. Create Pipeline
34+
35+Create `.gitlab-ci.yml`:
36+
37+```yaml
38+deploy:
39+ stage: deploy
40+ image: docker:24
41+ services:
42+ - docker:24-dind
43+ before_script:
44+ - apk add --no-cache curl
45+ - curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
46+ - chmod +x /usr/local/bin/gordon
47+ script:
48+ - gordon push --build
49+ --remote "$GORDON_REMOTE"
50+ --token "$GORDON_TOKEN"
51+ --no-confirm
52+ only:
53+ - tags
54+```
55+
56+Gordon auto-detects the version from `$CI_COMMIT_TAG`.
57+
58+## Pipeline Examples
59+
60+### Deploy on Tag Push
61+
62+```yaml
63+stages:
64+ - deploy
65+
66+deploy:
67+ stage: deploy
68+ image: docker:24
69+ services:
70+ - docker:24-dind
71+ before_script:
72+ - apk add --no-cache curl
73+ - curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
74+ - chmod +x /usr/local/bin/gordon
75+ script:
76+ - gordon push --build
77+ --remote "$GORDON_REMOTE"
78+ --token "$GORDON_TOKEN"
79+ --no-confirm
80+ rules:
81+ - if: $CI_COMMIT_TAG
82+```
83+
84+### Continuous Deployment
85+
86+Deploy on every push to main:
87+
88+```yaml
89+deploy:
90+ stage: deploy
91+ image: docker:24
92+ services:
93+ - docker:24-dind
94+ before_script:
95+ - apk add --no-cache curl
96+ - curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
97+ - chmod +x /usr/local/bin/gordon
98+ script:
99+ - gordon push --build
100+ --remote "$GORDON_REMOTE"
101+ --token "$GORDON_TOKEN"
102+ --no-confirm
103+ rules:
104+ - if: $CI_COMMIT_BRANCH == "main"
105+```
106+
107+### Manual Deployment
108+
109+```yaml
110+deploy:
111+ stage: deploy
112+ image: docker:24
113+ services:
114+ - docker:24-dind
115+ before_script:
116+ - apk add --no-cache curl
117+ - curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
118+ - chmod +x /usr/local/bin/gordon
119+ script:
120+ - gordon push --build
121+ --remote "$GORDON_REMOTE"
122+ --token "$GORDON_TOKEN"
123+ --no-confirm
124+ when: manual
125+```
126+
127+### With Build Arguments
128+
129+```yaml
130+deploy:
131+ stage: deploy
132+ image: docker:24
133+ services:
134+ - docker:24-dind
135+ before_script:
136+ - apk add --no-cache curl
137+ - curl -fsSL https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64 -o /usr/local/bin/gordon
138+ - chmod +x /usr/local/bin/gordon
139+ script:
140+ - gordon push --build
141+ --remote "$GORDON_REMOTE"
142+ --token "$GORDON_TOKEN"
143+ --build-arg NODE_ENV=production
144+ --build-arg API_URL=https://api.example.com
145+ --no-confirm
146+ rules:
147+ - if: $CI_COMMIT_TAG
148+```
149+
150+## Alternative: Docker-based Pipeline
151+
152+For environments where installing the Gordon binary is not desired:
153+
154+```yaml
155+deploy:
156+ stage: deploy
157+ image: docker:24
158+ services:
159+ - docker:24-dind
160+ script:
161+ - echo "$GORDON_TOKEN" | docker login "$GORDON_REGISTRY" -u "$GORDON_USERNAME" --password-stdin
162+ - docker build -t "$GORDON_REGISTRY/myapp:$CI_COMMIT_TAG" .
163+ - docker push "$GORDON_REGISTRY/myapp:$CI_COMMIT_TAG"
164+ rules:
165+ - if: $CI_COMMIT_TAG
166+```
167+
168+This requires additional CI/CD variables: `GORDON_REGISTRY` and `GORDON_USERNAME`.
169+Gordon auto-deploys when it receives the image.
170+
171+## Version Detection
172+
173+Gordon automatically detects the version tag from GitLab CI environment variables:
174+
175+| Variable | Example | Result |
176+|----------|---------|--------|
177+| `$CI_COMMIT_TAG` | `v1.2.0` | Tag `v1.2.0` |
178+| No tag | - | Falls back to `git describe` or `latest` |
179+
180+## Troubleshooting
181+
182+### Authentication Failed
183+
184+```
185+Error: failed to verify token
186+```
187+
188+Verify `GORDON_TOKEN` is correctly set and the token has not been revoked.
189+
190+### Docker-in-Docker Issues
191+
192+If using `docker:dind`, ensure the service is properly configured:
193+
194+```yaml
195+services:
196+ - docker:24-dind
197+variables:
198+ DOCKER_TLS_CERTDIR: "/certs"
199+```
200+
201+### Build Context
202+
203+GitLab CI clones your repository automatically. The build context defaults to the repository root.
204+
205+## Related
206+
207+- [GitHub Actions](./github-actions.md)
208+- [Generic CI](./generic-ci.md)
209+- [Deployment Overview](./index.md)
210+- [Authentication](../config/auth.md)
211+- [Push Command](../cli/push.md)
M docs/deployment/index.md +101 -115
@@ -1,41 +1,104 @@
11 # Deployment Overview
22
3-Strategies for deploying applications with Gordon.
3+Gordon deploys containers when you push images to its built-in registry. Three deployment methods are available depending on your workflow and infrastructure.
44
5-## Deployment Methods
5+## Recommended: gordon push
66
7-| Method | Use Case |
8-|--------|----------|
9-| Manual Push | Development, one-off deploys |
10-| GitHub Actions | Automated CI/CD |
11-| GitLab CI | Automated CI/CD |
12-| Generic CI | Any CI/CD system |
7+`gordon push --build --remote` is the simplest way to build, push, and deploy from CI/CD pipelines.
138
14-## Basic Deployment Workflow
9+- Single command: build + push + deploy
10+- Single secret (`GORDON_TOKEN`): auto-exchanges for a short-lived registry token
11+- Auto-detects version from CI environment (`$GITHUB_REF`, `$CI_COMMIT_TAG`, `$BUILD_SOURCEBRANCH`, or `git describe`)
12+- Chunked uploads (50MB chunks) — works behind Cloudflare and restrictive proxies
1513
16-### 1. Build Locally
14+```bash
15+gordon push --build --remote https://gordon.example.com --no-confirm
16+```
17+
18+## All Deployment Methods
19+
20+| Method | Best For | Secrets Needed | Registry Access | Deploy Control |
21+|--------|----------|----------------|-----------------|----------------|
22+| `gordon push` (Recommended) | CI/CD pipelines | 1 (`GORDON_TOKEN`) | Via gordon domain (HTTPS) | Explicit (CLI-triggered) |
23+| `docker push` | Simple setups, existing Docker workflows | 2 (`username` + `token`) | Via gordon domain (HTTPS) | Automatic (event-based) |
24+| Docker labels + auto-route | GitOps, zero-config deploys | 2 (`username` + `token`) | Via gordon domain (HTTPS) | Automatic (label-driven) |
25+
26+### Method 1: gordon push (Recommended)
27+
28+The Gordon CLI handles authentication, image building, and deployment in a single step.
29+
30+- Single token handles everything: admin API access + registry auth via automatic token exchange
31+- Version tag auto-detected from `$GITHUB_REF`, `$CI_COMMIT_TAG`, `$BUILD_SOURCEBRANCH`, or `git describe`
32+- Use `--no-deploy` for push-only workflows (useful for staging images without triggering deployment)
33+- Requires the Gordon binary on the CI runner
1734
1835 ```bash
19-docker build -t myapp .
36+# Build, push, and deploy
37+gordon push --build --remote https://gordon.example.com --no-confirm
38+
39+# Push only, no deploy
40+gordon push --build --remote https://gordon.example.com --no-deploy --no-confirm
2041 ```
2142
22-### 2. Tag for Registry
43+### Method 2: docker push
44+
45+Standard Docker workflow — no Gordon binary required on the runner.
46+
47+- Use `docker login`, `docker build`, and `docker push` as usual
48+- Gordon auto-deploys when it receives the image (event-based, no explicit trigger needed)
49+- No Gordon binary needed on the CI runner
50+- Registry endpoint is `gordon.example.com` (not a separate registry host)
2351
2452 ```bash
25-docker tag myapp registry.mydomain.com/myapp:latest
53+docker login -u ci-bot -p "$GORDON_TOKEN" gordon.example.com
54+docker build -t gordon.example.com/myapp:v1.2.0 .
55+docker push gordon.example.com/myapp:v1.2.0
56+```
57+
58+### Method 3: Docker labels + auto-route
59+
60+Add a `gordon.domain` label to your image and Gordon creates the route automatically on push.
61+
62+- Add `gordon.domain=app.example.com` label to your Dockerfile
63+- Push image — Gordon creates or updates the route without manual config
64+- Gated by the `auto_route_allowed_domains` allowlist in `gordon.toml`
65+- Best for GitOps workflows where routes are defined alongside the application
66+
67+```dockerfile
68+LABEL gordon.domain="app.example.com"
2669 ```
2770
28-### 3. Push to Deploy
71+See [Auto-Route](../config/auto-route.md) for configuration details.
72+
73+## Registry Access
74+
75+Gordon's registry is served through the main gordon domain over HTTPS on port 443. The internal registry port (5000) is never exposed externally. All push methods use `https://gordon.example.com/v2/...`.
76+
77+### Network Topologies
78+
79+| Setup | Configuration | Use Case |
80+|-------|--------------|----------|
81+| Public (default) | `auth.enabled = true` | Hosted CI runners (GitHub Actions, GitLab CI) |
82+| Tailscale only | `registry_allowed_ips = ["100.64.0.0/10"]` | Self-hosted runners in Tailnet |
83+| Localhost only | `auth.enabled = false` | Local development, single-machine deploys |
84+
85+## Token Setup
2986
3087 ```bash
31-docker push registry.mydomain.com/myapp:latest
88+# For gordon push (recommended) — needs admin scopes for route resolution and deploy
89+gordon auth token generate \
90+ --subject ci-bot \
91+ --scopes "push,pull,admin:routes:read,admin:config:write" \
92+ --expiry 0
93+
94+# For docker push — registry scopes only
95+gordon auth token generate \
96+ --subject ci-bot \
97+ --scopes "push,pull" \
98+ --expiry 0
3299 ```
33100
34-Gordon automatically:
35-1. Receives the image
36-2. Deploys a new container
37-3. Routes traffic to it
38-4. Stops the old container
101+Set the generated token as `GORDON_TOKEN` in your CI environment.
39102
40103 ## Version Strategies
41104
@@ -44,54 +107,48 @@ Gordon automatically:
44107 Always deploy the most recent build:
45108
46109 ```bash
47-docker tag myapp registry.mydomain.com/myapp:latest
48-docker push registry.mydomain.com/myapp:latest
110+docker tag myapp gordon.example.com/myapp:latest
111+docker push gordon.example.com/myapp:latest
49112 ```
50113
51-Configure route:
52114 ```toml
53115 [routes]
54-"app.mydomain.com" = "myapp:latest"
116+"app.example.com" = "myapp:latest"
55117 ```
56118
57119 ### Semantic Versioning
58120
59-Pin to specific versions:
121+Pin routes to specific versions and update config to roll forward:
60122
61123 ```bash
62-docker tag myapp registry.mydomain.com/myapp:v2.1.0
63-docker push registry.mydomain.com/myapp:v2.1.0
124+docker tag myapp gordon.example.com/myapp:v2.1.0
125+docker push gordon.example.com/myapp:v2.1.0
64126 ```
65127
66-Configure route:
67128 ```toml
68129 [routes]
69-"app.mydomain.com" = "myapp:v2.1.0"
130+"app.example.com" = "myapp:v2.1.0"
70131 ```
71132
72-Update config to deploy new version:
73-```toml
74-[routes]
75-"app.mydomain.com" = "myapp:v2.2.0"
76-```
133+To deploy a new version, update the tag in `gordon.toml` and push the new image.
77134
78135 ### Git SHA Tags
79136
80-Tag with commit hash for traceability:
137+Tag with commit hash for full traceability:
81138
82139 ```bash
83140 VERSION=$(git rev-parse --short HEAD)
84-docker tag myapp registry.mydomain.com/myapp:$VERSION
85-docker push registry.mydomain.com/myapp:$VERSION
141+docker tag myapp gordon.example.com/myapp:$VERSION
142+docker push gordon.example.com/myapp:$VERSION
86143 ```
87144
88145 ## Zero-Downtime Deployment
89146
90147 Gordon performs zero-downtime deployments by default:
91148
92-1. **New container starts** while old is still running
93-2. **Health check** waits for new container readiness
94-3. **Traffic switches** to new container
149+1. **New container starts** while the old one is still running
150+2. **Health check** waits for the new container to become ready
151+3. **Traffic switches** to the new container
95152 4. **Old container stops** after traffic moves
96153
97154 ```
@@ -103,83 +160,12 @@ New Container: [══════════════════
103160 ↑ start ↑ traffic routed
104161 ```
105162
106-## Environment-Specific Deployments
107-
108-### Development
109-
110-```toml
111-[routes]
112-"dev.mydomain.com" = "myapp:latest"
113-```
114-
115-```bash
116-docker push registry.mydomain.com/myapp:latest
117-```
118-
119-### Staging
120-
121-```toml
122-[routes]
123-"staging.mydomain.com" = "myapp:staging"
124-```
125-
126-```bash
127-docker tag myapp registry.mydomain.com/myapp:staging
128-docker push registry.mydomain.com/myapp:staging
129-```
130-
131-### Production
132-
133-```toml
134-[routes]
135-"app.mydomain.com" = "myapp:v2.1.0"
136-```
137-
138-```bash
139-docker tag myapp registry.mydomain.com/myapp:v2.1.0
140-docker push registry.mydomain.com/myapp:v2.1.0
141-# Then update gordon.toml and reload
142-```
143-
144-## Deployment Checklist
145-
146-Before deploying:
147-
148-- [ ] Build passes locally
149-- [ ] Tests pass
150-- [ ] Environment file configured (`~/.gordon/env/app_mydomain_com.env`)
151-- [ ] DNS pointing to Gordon server
152-- [ ] Route configured in `gordon.toml`
153-
154-After deploying:
155-
156-- [ ] Container starts successfully
157-- [ ] Application responds to requests
158-- [ ] Logs show no errors
159-- [ ] Health checks pass
160-
161-## Monitoring Deployments
162-
163-### Watch Logs
164-
165-```bash
166-gordon logs -f
167-```
168-
169-### Check Container Status
170-
171-```bash
172-docker ps | grep gordon
173-```
174-
175-### Verify Routing
176-
177-```bash
178-curl -I https://app.mydomain.com
179-```
180-
181163 ## Related
182164
183165 - [GitHub Actions](./github-actions.md)
166+- [GitLab CI](./gitlab-ci.md)
167+- [Generic CI](./generic-ci.md)
184168 - [Rollback](./rollback.md)
185169 - [Routes Configuration](../config/routes.md)
170+- [Authentication](../config/auth.md)
171+- [Auto-Route](../config/auto-route.md)
@@ -1,41 +1,104 @@
1 # Deployment Overview1 # Deployment Overview
2 2
3-Strategies for deploying applications with Gordon.3+Gordon deploys containers when you push images to its built-in registry. Three deployment methods are available depending on your workflow and infrastructure.
4 4
5-## Deployment Methods5+## Recommended: gordon push
6 6
7-| Method | Use Case |7+`gordon push --build --remote` is the simplest way to build, push, and deploy from CI/CD pipelines.
8-|--------|----------|
9-| Manual Push | Development, one-off deploys |
10-| GitHub Actions | Automated CI/CD |
11-| GitLab CI | Automated CI/CD |
12-| Generic CI | Any CI/CD system |
13 8
14-## Basic Deployment Workflow9+- Single command: build + push + deploy
10+- Single secret (`GORDON_TOKEN`): auto-exchanges for a short-lived registry token
11+- Auto-detects version from CI environment (`$GITHUB_REF`, `$CI_COMMIT_TAG`, `$BUILD_SOURCEBRANCH`, or `git describe`)
12+- Chunked uploads (50MB chunks) — works behind Cloudflare and restrictive proxies
15 13
16-### 1. Build Locally14+```bash
15+gordon push --build --remote https://gordon.example.com --no-confirm
16+```
17+
18+## All Deployment Methods
19+
20+| Method | Best For | Secrets Needed | Registry Access | Deploy Control |
21+|--------|----------|----------------|-----------------|----------------|
22+| `gordon push` (Recommended) | CI/CD pipelines | 1 (`GORDON_TOKEN`) | Via gordon domain (HTTPS) | Explicit (CLI-triggered) |
23+| `docker push` | Simple setups, existing Docker workflows | 2 (`username` + `token`) | Via gordon domain (HTTPS) | Automatic (event-based) |
24+| Docker labels + auto-route | GitOps, zero-config deploys | 2 (`username` + `token`) | Via gordon domain (HTTPS) | Automatic (label-driven) |
25+
26+### Method 1: gordon push (Recommended)
27+
28+The Gordon CLI handles authentication, image building, and deployment in a single step.
29+
30+- Single token handles everything: admin API access + registry auth via automatic token exchange
31+- Version tag auto-detected from `$GITHUB_REF`, `$CI_COMMIT_TAG`, `$BUILD_SOURCEBRANCH`, or `git describe`
32+- Use `--no-deploy` for push-only workflows (useful for staging images without triggering deployment)
33+- Requires the Gordon binary on the CI runner
17 34
18 ```bash35 ```bash
19-docker build -t myapp .36+# Build, push, and deploy
37+gordon push --build --remote https://gordon.example.com --no-confirm
38+
39+# Push only, no deploy
40+gordon push --build --remote https://gordon.example.com --no-deploy --no-confirm
20 ```41 ```
21 42
22-### 2. Tag for Registry43+### Method 2: docker push
44+
45+Standard Docker workflow — no Gordon binary required on the runner.
46+
47+- Use `docker login`, `docker build`, and `docker push` as usual
48+- Gordon auto-deploys when it receives the image (event-based, no explicit trigger needed)
49+- No Gordon binary needed on the CI runner
50+- Registry endpoint is `gordon.example.com` (not a separate registry host)
23 51
24 ```bash52 ```bash
25-docker tag myapp registry.mydomain.com/myapp:latest53+docker login -u ci-bot -p "$GORDON_TOKEN" gordon.example.com
54+docker build -t gordon.example.com/myapp:v1.2.0 .
55+docker push gordon.example.com/myapp:v1.2.0
56+```
57+
58+### Method 3: Docker labels + auto-route
59+
60+Add a `gordon.domain` label to your image and Gordon creates the route automatically on push.
61+
62+- Add `gordon.domain=app.example.com` label to your Dockerfile
63+- Push image — Gordon creates or updates the route without manual config
64+- Gated by the `auto_route_allowed_domains` allowlist in `gordon.toml`
65+- Best for GitOps workflows where routes are defined alongside the application
66+
67+```dockerfile
68+LABEL gordon.domain="app.example.com"
26 ```69 ```
27 70
28-### 3. Push to Deploy71+See [Auto-Route](../config/auto-route.md) for configuration details.
72+
73+## Registry Access
74+
75+Gordon's registry is served through the main gordon domain over HTTPS on port 443. The internal registry port (5000) is never exposed externally. All push methods use `https://gordon.example.com/v2/...`.
76+
77+### Network Topologies
78+
79+| Setup | Configuration | Use Case |
80+|-------|--------------|----------|
81+| Public (default) | `auth.enabled = true` | Hosted CI runners (GitHub Actions, GitLab CI) |
82+| Tailscale only | `registry_allowed_ips = ["100.64.0.0/10"]` | Self-hosted runners in Tailnet |
83+| Localhost only | `auth.enabled = false` | Local development, single-machine deploys |
84+
85+## Token Setup
29 86
30 ```bash87 ```bash
31-docker push registry.mydomain.com/myapp:latest88+# For gordon push (recommended) — needs admin scopes for route resolution and deploy
89+gordon auth token generate \
90+ --subject ci-bot \
91+ --scopes "push,pull,admin:routes:read,admin:config:write" \
92+ --expiry 0
93+
94+# For docker push — registry scopes only
95+gordon auth token generate \
96+ --subject ci-bot \
97+ --scopes "push,pull" \
98+ --expiry 0
32 ```99 ```
33 100
34-Gordon automatically:101+Set the generated token as `GORDON_TOKEN` in your CI environment.
35-1. Receives the image
36-2. Deploys a new container
37-3. Routes traffic to it
38-4. Stops the old container
39 102
40 ## Version Strategies103 ## Version Strategies
41 104
@@ -44,54 +107,48 @@ Gordon automatically:
44 Always deploy the most recent build:107 Always deploy the most recent build:
45 108
46 ```bash109 ```bash
47-docker tag myapp registry.mydomain.com/myapp:latest110+docker tag myapp gordon.example.com/myapp:latest
48-docker push registry.mydomain.com/myapp:latest111+docker push gordon.example.com/myapp:latest
49 ```112 ```
50 113
51-Configure route:
52 ```toml114 ```toml
53 [routes]115 [routes]
54-"app.mydomain.com" = "myapp:latest"116+"app.example.com" = "myapp:latest"
55 ```117 ```
56 118
57 ### Semantic Versioning119 ### Semantic Versioning
58 120
59-Pin to specific versions:121+Pin routes to specific versions and update config to roll forward:
60 122
61 ```bash123 ```bash
62-docker tag myapp registry.mydomain.com/myapp:v2.1.0124+docker tag myapp gordon.example.com/myapp:v2.1.0
63-docker push registry.mydomain.com/myapp:v2.1.0125+docker push gordon.example.com/myapp:v2.1.0
64 ```126 ```
65 127
66-Configure route:
67 ```toml128 ```toml
68 [routes]129 [routes]
69-"app.mydomain.com" = "myapp:v2.1.0"130+"app.example.com" = "myapp:v2.1.0"
70 ```131 ```
71 132
72-Update config to deploy new version:133+To deploy a new version, update the tag in `gordon.toml` and push the new image.
73-```toml
74-[routes]
75-"app.mydomain.com" = "myapp:v2.2.0"
76-```
77 134
78 ### Git SHA Tags135 ### Git SHA Tags
79 136
80-Tag with commit hash for traceability:137+Tag with commit hash for full traceability:
81 138
82 ```bash139 ```bash
83 VERSION=$(git rev-parse --short HEAD)140 VERSION=$(git rev-parse --short HEAD)
84-docker tag myapp registry.mydomain.com/myapp:$VERSION141+docker tag myapp gordon.example.com/myapp:$VERSION
85-docker push registry.mydomain.com/myapp:$VERSION142+docker push gordon.example.com/myapp:$VERSION
86 ```143 ```
87 144
88 ## Zero-Downtime Deployment145 ## Zero-Downtime Deployment
89 146
90 Gordon performs zero-downtime deployments by default:147 Gordon performs zero-downtime deployments by default:
91 148
92-1. **New container starts** while old is still running149+1. **New container starts** while the old one is still running
93-2. **Health check** waits for new container readiness150+2. **Health check** waits for the new container to become ready
94-3. **Traffic switches** to new container151+3. **Traffic switches** to the new container
95 4. **Old container stops** after traffic moves152 4. **Old container stops** after traffic moves
96 153
97 ```154 ```
@@ -103,83 +160,12 @@ New Container: [══════════════════
103 ↑ start ↑ traffic routed160 ↑ start ↑ traffic routed
104 ```161 ```
105 162
106-## Environment-Specific Deployments
107-
108-### Development
109-
110-```toml
111-[routes]
112-"dev.mydomain.com" = "myapp:latest"
113-```
114-
115-```bash
116-docker push registry.mydomain.com/myapp:latest
117-```
118-
119-### Staging
120-
121-```toml
122-[routes]
123-"staging.mydomain.com" = "myapp:staging"
124-```
125-
126-```bash
127-docker tag myapp registry.mydomain.com/myapp:staging
128-docker push registry.mydomain.com/myapp:staging
129-```
130-
131-### Production
132-
133-```toml
134-[routes]
135-"app.mydomain.com" = "myapp:v2.1.0"
136-```
137-
138-```bash
139-docker tag myapp registry.mydomain.com/myapp:v2.1.0
140-docker push registry.mydomain.com/myapp:v2.1.0
141-# Then update gordon.toml and reload
142-```
143-
144-## Deployment Checklist
145-
146-Before deploying:
147-
148-- [ ] Build passes locally
149-- [ ] Tests pass
150-- [ ] Environment file configured (`~/.gordon/env/app_mydomain_com.env`)
151-- [ ] DNS pointing to Gordon server
152-- [ ] Route configured in `gordon.toml`
153-
154-After deploying:
155-
156-- [ ] Container starts successfully
157-- [ ] Application responds to requests
158-- [ ] Logs show no errors
159-- [ ] Health checks pass
160-
161-## Monitoring Deployments
162-
163-### Watch Logs
164-
165-```bash
166-gordon logs -f
167-```
168-
169-### Check Container Status
170-
171-```bash
172-docker ps | grep gordon
173-```
174-
175-### Verify Routing
176-
177-```bash
178-curl -I https://app.mydomain.com
179-```
180-
181 ## Related163 ## Related
182 164
183 - [GitHub Actions](./github-actions.md)165 - [GitHub Actions](./github-actions.md)
166+- [GitLab CI](./gitlab-ci.md)
167+- [Generic CI](./generic-ci.md)
184 - [Rollback](./rollback.md)168 - [Rollback](./rollback.md)
185 - [Routes Configuration](../config/routes.md)169 - [Routes Configuration](../config/routes.md)
170+- [Authentication](../config/auth.md)
171+- [Auto-Route](../config/auto-route.md)
M docs/index.md +3 -1
@@ -60,8 +60,10 @@ Gordon runs on your VPS and provides:
6060
6161 ### Deployment
6262
63-- [Deployment Overview](./deployment/index.md) - Deployment strategies
63+- [Deployment Overview](./deployment/index.md) - Deployment strategies and methods
6464 - [GitHub Actions](./deployment/github-actions.md) - CI/CD with GitHub
65+- [GitLab CI](./deployment/gitlab-ci.md) - CI/CD with GitLab
66+- [Generic CI](./deployment/generic-ci.md) - Jenkins, CircleCI, Drone, and others
6567 - [Rollback](./deployment/rollback.md) - Version management and rollback
6668
6769 ### Reference
@@ -60,8 +60,10 @@ Gordon runs on your VPS and provides:
60 60
61 ### Deployment61 ### Deployment
62 62
63-- [Deployment Overview](./deployment/index.md) - Deployment strategies63+- [Deployment Overview](./deployment/index.md) - Deployment strategies and methods
64 - [GitHub Actions](./deployment/github-actions.md) - CI/CD with GitHub64 - [GitHub Actions](./deployment/github-actions.md) - CI/CD with GitHub
65+- [GitLab CI](./deployment/gitlab-ci.md) - CI/CD with GitLab
66+- [Generic CI](./deployment/generic-ci.md) - Jenkins, CircleCI, Drone, and others
65 - [Rollback](./deployment/rollback.md) - Version management and rollback67 - [Rollback](./deployment/rollback.md) - Version management and rollback
66 68
67 ### Reference69 ### Reference

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close