Skip to content

Commit 621eb68

Browse files
committed
fix(ci): adapt previous CI workflow
Signed-off-by: Andrey Kolkov <androndo@gmail.com>
1 parent 3cb469f commit 621eb68

9 files changed

Lines changed: 303 additions & 34 deletions

File tree

.github/release-drafter.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name-template: 'v$RESOLVED_VERSION'
2+
tag-template: 'v$RESOLVED_VERSION'
3+
categories:
4+
- title: 'Features'
5+
labels:
6+
- 'feature'
7+
- 'enhancement'
8+
- title: 'Bug Fixes'
9+
labels:
10+
- 'bugfix'
11+
- title: 'Maintenance'
12+
labels:
13+
- 'chore'
14+
- 'dependencies'
15+
- 'documentation'
16+
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
17+
change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks.
18+
version-resolver:
19+
major:
20+
labels:
21+
- 'major'
22+
minor:
23+
labels:
24+
- 'minor'
25+
patch:
26+
labels:
27+
- 'patch'
28+
default: patch
29+
exclude-labels:
30+
- 'skip-changelog'
31+
autolabeler:
32+
- label: 'api-change'
33+
files:
34+
- 'api/**'
35+
- label: 'controllers'
36+
files:
37+
- 'controllers/**'
38+
- 'internal/**'
39+
- label: 'bugfix'
40+
branch:
41+
- '/fix\/.+/'
42+
- '/bugfix\/.+/'
43+
- label: 'feature'
44+
branch:
45+
- '/feature\/.+/'
46+
- '/feat\/.+/'
47+
- label: 'enhancement'
48+
branch:
49+
- '/enh\/.+/'
50+
- label: 'chore'
51+
branch:
52+
- '/chore\/.+/'
53+
- label: 'dependencies'
54+
branch:
55+
- '/deps\/.+/'
56+
- '/renovate\/.+/'
57+
- label: 'documentation'
58+
files:
59+
- '**/*.md'
60+
branch:
61+
- '/docs\/.+/'
62+
template: |
63+
## Changes
64+
$CHANGES

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: CI
22

33
on:
44
pull_request:
5-
branches: [ master ]
5+
branches: [ main ]
66
push:
7-
branches: [ master ]
7+
branches: [ main ]
88

99
jobs:
1010
verify:
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
name: Docker publish
2+
3+
# Tag-based image release. Pushing a semver tag (e.g. v0.5.0) builds the
4+
# operator image multi-arch, pushes it to GHCR under this repo's name, and
5+
# signs it with cosign. This is the same shape as the legacy v1alpha1 release
6+
# process, retargeted at ghcr.io/<owner>/<repo> via the built-in GITHUB_TOKEN
7+
# (no Docker Hub secrets needed).
8+
#
9+
# Release order: push the tag FIRST (this builds ghcr.io/.../etcd-operator:<tag>),
10+
# then publish the GitHub release for that tag — release-assets.yml renders the
11+
# install manifests pointing at this image.
12+
13+
on:
14+
push:
15+
tags: [ 'v*.*.*' ]
16+
17+
env:
18+
REGISTRY: ghcr.io
19+
# github.repository is <owner>/<repo>, e.g. cozystack/etcd-operator
20+
IMAGE_NAME: ${{ github.repository }}
21+
22+
jobs:
23+
build:
24+
runs-on: ubuntu-22.04
25+
permissions:
26+
contents: read
27+
packages: write
28+
# Needed for the keyless cosign identity challenge (sigstore/fulcio).
29+
id-token: write
30+
31+
steps:
32+
- name: Checkout repository
33+
uses: actions/checkout@v4
34+
35+
- name: Install cosign
36+
uses: sigstore/cosign-installer@v3.5.0
37+
38+
- name: Set up Docker Buildx
39+
uses: docker/setup-buildx-action@v3.3.0
40+
41+
- name: Log into registry ${{ env.REGISTRY }}
42+
uses: docker/login-action@v3.2.0
43+
with:
44+
registry: ${{ env.REGISTRY }}
45+
username: ${{ github.actor }}
46+
password: ${{ secrets.GITHUB_TOKEN }}
47+
48+
- name: Extract Docker metadata
49+
id: meta
50+
uses: docker/metadata-action@v5.5.1
51+
with:
52+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
53+
# Pin the published tag to the exact git ref (e.g. v0.5.0). This is
54+
# the SAME source release-assets.yml uses for the IMG it bakes into
55+
# the install manifest (its RELEASE_TAG is github.ref_name too), so
56+
# the image that ships and the image the manifest references are
57+
# provably identical. Don't rely on metadata-action's implicit
58+
# default: it also emits a moving `latest` and its default tag set is
59+
# easy to misread — explicit keeps the publish/manifest contract clear.
60+
tags: |
61+
type=raw,value=${{ github.ref_name }}
62+
63+
- name: Build and push Docker image
64+
id: build-and-push
65+
uses: docker/build-push-action@v6
66+
with:
67+
context: .
68+
push: true
69+
tags: ${{ steps.meta.outputs.tags }}
70+
labels: ${{ steps.meta.outputs.labels }}
71+
platforms: linux/amd64,linux/arm64
72+
cache-from: type=gha
73+
cache-to: type=gha,mode=max
74+
75+
- name: Sign the published Docker image
76+
env:
77+
TAGS: ${{ steps.meta.outputs.tags }}
78+
DIGEST: ${{ steps.build-and-push.outputs.digest }}
79+
run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}

.github/workflows/publish.yml

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Upload release assets
2+
3+
# When a GitHub release is created for a tag, render the install manifests for
4+
# that tag's image and attach them to the release. `make build-dist-manifests`
5+
# sets the `controller` image (and, via the kustomize replacement in
6+
# config/default, the manager's OPERATOR_IMAGE env) to the released ref, so the
7+
# attached YAML deploys the matching operator and its snapshot/restore agent.
8+
9+
on:
10+
release:
11+
types: [ created ]
12+
workflow_dispatch:
13+
14+
env:
15+
REGISTRY: ghcr.io
16+
IMAGE_NAME: ${{ github.repository }}
17+
18+
jobs:
19+
release-assets:
20+
runs-on: ubuntu-22.04
21+
permissions:
22+
contents: write
23+
steps:
24+
- uses: actions/checkout@v4
25+
26+
- uses: actions/setup-go@v5
27+
with:
28+
go-version-file: go.mod
29+
cache: true
30+
31+
- name: Resolve release tag
32+
run: echo "RELEASE_TAG=${{ github.ref_name }}" >> $GITHUB_ENV
33+
34+
- name: Render install manifests
35+
run: make build-dist-manifests IMG=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${RELEASE_TAG}
36+
37+
- uses: svenstaro/upload-release-action@2.9.0
38+
with:
39+
repo_token: ${{ secrets.GITHUB_TOKEN }}
40+
file: dist/etcd-operator.yaml
41+
asset_name: etcd-operator.yaml
42+
tag: ${{ github.ref }}
43+
overwrite: true
44+
45+
- uses: svenstaro/upload-release-action@2.9.0
46+
with:
47+
repo_token: ${{ secrets.GITHUB_TOKEN }}
48+
file: dist/etcd-operator.crds.yaml
49+
asset_name: etcd-operator.crds.yaml
50+
tag: ${{ github.ref }}
51+
overwrite: true
52+
53+
- uses: svenstaro/upload-release-action@2.9.0
54+
with:
55+
repo_token: ${{ secrets.GITHUB_TOKEN }}
56+
file: dist/etcd-operator.non-crds.yaml
57+
asset_name: etcd-operator.non-crds.yaml
58+
tag: ${{ github.ref }}
59+
overwrite: true
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Release Drafter
2+
3+
# Maintains a draft GitHub release on main, accumulating merged-PR titles into
4+
# categorised notes. Publishing that draft for a tag is what triggers
5+
# release-assets.yml; pushing the tag is what triggers docker-publish.yml.
6+
7+
on:
8+
push:
9+
branches: [ main ]
10+
# pull_request_target runs in the context of the BASE branch (main) with a
11+
# read/write token, which is what lets the autolabeler label PRs from forks.
12+
# It is used ONLY to read PR metadata (title, labels, changed-file globs).
13+
pull_request_target:
14+
types: [ opened, reopened, synchronize ]
15+
workflow_dispatch:
16+
17+
jobs:
18+
release-drafter:
19+
runs-on: ubuntu-22.04
20+
permissions:
21+
contents: write
22+
pull-requests: write
23+
steps:
24+
# SECURITY: never add `actions/checkout` of the PR head (or run any code
25+
# from the PR) in this job. pull_request_target grants a write token and
26+
# secrets while running base-branch config; checking out + executing fork
27+
# code under it is the canonical fork-to-RCE pattern. release-drafter
28+
# touches no repo code, so this job stays safe as long as nothing here
29+
# checks out untrusted refs.
30+
- uses: release-drafter/release-drafter@v6.0.0
31+
with:
32+
disable-releaser: ${{ github.ref != 'refs/heads/main' }}
33+
config-name: release-drafter.yml
34+
commitish: main
35+
env:
36+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ bin
1010
/kubectl-etcd
1111
# etcd-migrate tool: same rule — build to bin/, never commit the root-level artifact
1212
/etcd-migrate
13+
# release install manifests rendered by `make build-dist-manifests`; the
14+
# release-assets workflow regenerates and attaches these per tag
15+
/dist
1316

1417
# Test binary, build with `go test -c`
1518
*.test

Makefile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,21 @@ docker-buildx: test ## Build and push docker image for the manager for cross-pla
115115
- docker buildx rm project-v3-builder
116116
rm Dockerfile.cross
117117

118+
.PHONY: build-dist-manifests
119+
build-dist-manifests: manifests generate kustomize yq ## Render the release install manifests into dist/ for IMG.
120+
# Produces the YAMLs the release-assets workflow attaches to a tag:
121+
# dist/etcd-operator.yaml – everything (CRDs + deployment)
122+
# dist/etcd-operator.crds.yaml – CRDs only
123+
# dist/etcd-operator.non-crds.yaml – everything except CRDs
124+
# Setting the `controller` image also propagates into the manager's
125+
# OPERATOR_IMAGE env via the kustomize replacement in config/default, so
126+
# the snapshot/restore agent runs the same ref. Pass IMG=<registry>/etcd-operator:<tag>.
127+
mkdir -p dist
128+
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
129+
$(KUSTOMIZE) build config/default > dist/etcd-operator.yaml
130+
$(KUSTOMIZE) build config/default | $(YQ) eval 'select(.kind != "CustomResourceDefinition")' - > dist/etcd-operator.non-crds.yaml
131+
$(KUSTOMIZE) build config/default | $(YQ) eval 'select(.kind == "CustomResourceDefinition")' - > dist/etcd-operator.crds.yaml
132+
118133
##@ Deployment
119134

120135
ifndef ignore-not-found
@@ -148,12 +163,14 @@ $(LOCALBIN):
148163
## Tool Versions
149164
KUSTOMIZE_VERSION ?= v5.6.0
150165
CONTROLLER_TOOLS_VERSION ?= v0.18.0
166+
YQ_VERSION ?= v4.44.1
151167

152168
## Tool Binaries (version-suffixed so a version bump auto-triggers reinstall
153169
## and stale builds of an old version stay on disk alongside the new one).
154170
KUSTOMIZE ?= $(LOCALBIN)/kustomize-$(KUSTOMIZE_VERSION)
155171
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen-$(CONTROLLER_TOOLS_VERSION)
156172
ENVTEST ?= $(LOCALBIN)/setup-envtest
173+
YQ ?= $(LOCALBIN)/yq-$(YQ_VERSION)
157174

158175
# go-install-tool installs $2@$3 under $1. `go install` drops the binary at
159176
# $LOCALBIN/<basename>, so we rename it after install to the version-suffixed
@@ -182,3 +199,8 @@ $(CONTROLLER_GEN): $(LOCALBIN)
182199
envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.
183200
$(ENVTEST): $(LOCALBIN)
184201
test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest
202+
203+
.PHONY: yq
204+
yq: $(YQ) ## Download yq locally if necessary.
205+
$(YQ): $(LOCALBIN)
206+
$(call go-install-tool,$(YQ),github.com/mikefarah/yq/v4,$(YQ_VERSION))

docs/installation.md

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,44 @@ For the operator's runtime behaviour see [concepts](concepts.md); for day-2 oper
1515

1616
Workload-side: every etcd Pod runs as UID 65532 with `runAsNonRoot=true`, `allowPrivilegeEscalation=false`, all capabilities dropped, and `seccompProfile=RuntimeDefault`. The Pods comply with the `restricted` PodSecurity profile. If your cluster enforces a stricter policy, see `controllers/etcdmember_controller.go`'s `buildPod` for the exact security context the operator emits and adjust accordingly.
1717

18-
## Quick deploy
18+
## Install from a release
19+
20+
Tagged releases publish a signed multi-arch operator image to GHCR and attach
21+
ready-to-apply install manifests to the GitHub release — no checkout, no build,
22+
no registry of your own. This is the recommended path for consuming a release.
23+
24+
```sh
25+
# Pick a released version (see https://github.com/cozystack/etcd-operator/releases).
26+
VERSION=v0.5.0
27+
28+
# Everything (CRDs + namespace + RBAC + controller Deployment + Service):
29+
kubectl apply -f https://github.com/cozystack/etcd-operator/releases/download/$VERSION/etcd-operator.yaml
30+
```
31+
32+
The manifest already points the manager (and its `OPERATOR_IMAGE`, used for
33+
snapshot/restore Pods) at `ghcr.io/cozystack/etcd-operator:$VERSION` — the same
34+
tag whose image the release published, so there is nothing to substitute.
35+
36+
If you split CRDs from the rest (e.g. CRDs are applied by a separate
37+
cluster-admin step, or server-side-applied to dodge the annotation size limit):
38+
39+
```sh
40+
kubectl apply --server-side -f https://github.com/cozystack/etcd-operator/releases/download/$VERSION/etcd-operator.crds.yaml
41+
kubectl apply -f https://github.com/cozystack/etcd-operator/releases/download/$VERSION/etcd-operator.non-crds.yaml
42+
```
43+
44+
The image is cosign-signed (keyless). To verify before deploying:
45+
46+
```sh
47+
cosign verify ghcr.io/cozystack/etcd-operator:$VERSION \
48+
--certificate-identity-regexp 'https://github.com/cozystack/etcd-operator/.github/workflows/.+' \
49+
--certificate-oidc-issuer https://token.actions.githubusercontent.com
50+
```
51+
52+
To pull a prebuilt image without the release manifests (e.g. to feed your own
53+
overlay), the image ref is `ghcr.io/cozystack/etcd-operator:<tag>`.
54+
55+
## Quick deploy (build from source)
1956

2057
The repo's Makefile drives a complete install. From a checkout:
2158

0 commit comments

Comments
 (0)