mirror of
https://code.forgejo.org/forgejo/runner.git
synced 2025-07-27 17:28:35 +00:00
Improve doc and add full example for Kubernetes (#657)
Reviewed-on: https://code.forgejo.org/forgejo/runner/pulls/657 Reviewed-by: earl-warren <earl-warren@noreply.code.forgejo.org> Co-authored-by: Grégoire Bellon-Gervais <gregoire.bellon-gervais@docaposte.fr> Co-committed-by: Grégoire Bellon-Gervais <gregoire.bellon-gervais@docaposte.fr>
This commit is contained in:
parent
2fbe500d36
commit
d871b38c8d
3 changed files with 181 additions and 44 deletions
|
@ -1,7 +1,20 @@
|
||||||
## Kubernetes Docker in Docker Deployment
|
# Kubernetes Docker in Docker Deployment
|
||||||
|
|
||||||
Registers Kubernetes pod runners using [offline registration](https://forgejo.org/docs/v1.21/admin/actions/#offline-registration), allowing the scaling of runners as needed.
|
Registers Kubernetes Pod runners using [offline registration](https://forgejo.org/docs/latest/admin/runner-installation/#offline-registration), allowing the scaling of runners as needed.
|
||||||
|
|
||||||
NOTE: Docker in Docker (dind) requires elevated privileges on Kubernetes. The current way to achieve this is to set the pod `SecurityContext` to `privileged`. Keep in mind that this is a potential security issue that has the potential for a malicious application to break out of the container context.
|
NOTE: Docker in Docker (dind) requires elevated privileges on Kubernetes. The current way to achieve this is to set the pod `SecurityContext` to `privileged`. Keep in mind that this is a potential security issue that has the potential for a malicious application to break out of the container context.
|
||||||
|
|
||||||
[`dind-docker.yaml`](dind-docker.yaml) creates a deployment and secret for Kubernetes to act as a runner. The Docker credentials are re-generated each time the pod connects and does not need to be persisted.
|
[`dind-docker.yaml`](dind-docker.yaml) creates a Deployment and Secret for Kubernetes to act as a runner. The Docker credentials are re-generated each time the pod connects and does not need to be persisted.
|
||||||
|
|
||||||
|
Do not forget to update `FORGEJO_INSTANCE_URL` value.
|
||||||
|
|
||||||
|
# Build you first container image
|
||||||
|
First, you will need to generate an Applications Access token with the permission `write:package` (see [doc](https://forgejo.org/docs/latest/user/token-scope/)), usually from https://your-forgejo.fr/user/settings/applications.
|
||||||
|
|
||||||
|
Then, you will create 2 forgejo Actions [Secrets](https://forgejo.org/docs/latest/user/actions/#secrets):
|
||||||
|
- `USERNAME_WRITE_REPOSITORY` containing Token name
|
||||||
|
- `PASSWORD_WRITE_REPOSITORY` containing Token value
|
||||||
|
|
||||||
|
And you can then, use the [`build.yaml`](build.yaml) file provided as exemple.
|
||||||
|
|
||||||
|
This file must be created in your repository under: `.forgejo/workflows/build.yaml`
|
||||||
|
|
48
examples/kubernetes/build.yaml
Normal file
48
examples/kubernetes/build.yaml
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
name: build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- airflow/Dockerfile # Trigger only if Dockerfile is changed
|
||||||
|
- airflow/requirements.txt # Trigger only if requirements.txt is changed
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: docker
|
||||||
|
steps:
|
||||||
|
- name: Checkout the repo
|
||||||
|
uses: https://data.forgejo.org/actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Extract the current airflow version from the Dockerfile and set it in a variable name airflow_version
|
||||||
|
id: extract_airflow_version
|
||||||
|
run: echo "::set-output name=airflow_version::$(grep -oP '(?<=FROM apache/airflow:)[0-9]+\.[0-9]+\.[0-9]+' airflow/Dockerfile)"
|
||||||
|
|
||||||
|
- name: Add variables
|
||||||
|
id: add-vars
|
||||||
|
run: |
|
||||||
|
echo "::set-output name=registry::${GITHUB_SERVER_URL#*//}" # built-in env variable
|
||||||
|
echo "::set-output name=repository::${GITHUB_REPOSITORY}" # built-in env variable
|
||||||
|
echo "::set-output name=app::airflow"
|
||||||
|
echo "::set-output name=context::airflow" # Dockerfile is in airflow folder, so context is airflow folder not .
|
||||||
|
echo "::set-output name=dockerfile::airflow/Dockerfile" # Dockerfile path
|
||||||
|
echo "::set-output name=tag::${{ steps.extract_airflow_version.outputs.airflow_version }}-${{ github.sha}}"
|
||||||
|
|
||||||
|
- name: Docker CLI installation
|
||||||
|
run: |
|
||||||
|
apt update
|
||||||
|
apt install -y ca-certificates curl
|
||||||
|
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||||
|
sh get-docker.sh
|
||||||
|
|
||||||
|
- name: Login to Container Registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ${{ steps.add-vars.outputs.registry }}
|
||||||
|
username: ${{ secrets.USERNAME_WRITE_REPOSITORY }}
|
||||||
|
password: ${{ secrets.PASSWORD_WRITE_REPOSITORY }}
|
||||||
|
|
||||||
|
- name: Image build
|
||||||
|
run: docker build -f ${{ steps.add-vars.outputs.dockerfile }} -t ${{ steps.add-vars.outputs.registry }}/${{ steps.add-vars.outputs.repository }}:${{ steps.add-vars.outputs.app }}-${{ steps.add-vars.outputs.tag }} ${{ steps.add-vars.outputs.context }}
|
||||||
|
|
||||||
|
- name: Image push to registry
|
||||||
|
run: docker push ${{steps.add-vars.outputs.registry }}/${{steps.add-vars.outputs.repository }}:${{steps.add-vars.outputs.app }}-${{ steps.add-vars.outputs.tag }}
|
|
@ -3,43 +3,58 @@
|
||||||
# Alternatively, create this with
|
# Alternatively, create this with
|
||||||
# kubectl create secret generic runner-secret --from-literal=token=your_offline_token_here
|
# kubectl create secret generic runner-secret --from-literal=token=your_offline_token_here
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
stringData:
|
|
||||||
token: your_offline_secret_here
|
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: runner-secret
|
name: runner-secret
|
||||||
|
stringData:
|
||||||
|
token: your_offline_secret_here # Replace with your Forgejo offline registration token
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
|
name: forgejo-runner
|
||||||
labels:
|
labels:
|
||||||
app: forgejo-runner
|
app: forgejo-runner
|
||||||
name: forgejo-runner
|
app.kubernetes.io/component: forgejo-runner
|
||||||
|
app.kubernetes.io/instance: forgejo-runner
|
||||||
|
app.kubernetes.io/managed-by: Kustomize
|
||||||
|
app.kubernetes.io/name: forgejo-runner
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: '1'
|
||||||
spec:
|
spec:
|
||||||
# Two replicas means that if one is busy, the other can pick up jobs.
|
|
||||||
replicas: 2
|
replicas: 2
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: forgejo-runner
|
app: forgejo-runner
|
||||||
strategy: {}
|
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
creationTimestamp: null
|
name: forgejo-runner
|
||||||
labels:
|
labels:
|
||||||
app: forgejo-runner
|
app: forgejo-runner
|
||||||
|
app.kubernetes.io/component: forgejo-runner
|
||||||
|
app.kubernetes.io/instance: forgejo-runner
|
||||||
|
app.kubernetes.io/managed-by: Kustomize
|
||||||
|
app.kubernetes.io/name: forgejo-runner
|
||||||
spec:
|
spec:
|
||||||
|
automountServiceAccountToken: false
|
||||||
restartPolicy: Always
|
restartPolicy: Always
|
||||||
volumes:
|
|
||||||
- name: docker-certs
|
|
||||||
emptyDir: {}
|
|
||||||
- name: runner-data
|
|
||||||
emptyDir: {}
|
|
||||||
# Initialise our configuration file using offline registration
|
|
||||||
# https://forgejo.org/docs/v1.21/admin/actions/#offline-registration
|
|
||||||
initContainers:
|
initContainers:
|
||||||
- name: runner-register
|
- name: runner-register
|
||||||
image: code.forgejo.org/forgejo/runner:6.0.1
|
image: code.forgejo.org/forgejo/runner:6.4.0
|
||||||
command: ["forgejo-runner", "register", "--no-interactive", "--token", $(RUNNER_SECRET), "--name", $(RUNNER_NAME), "--instance", $(FORGEJO_INSTANCE_URL)]
|
command:
|
||||||
|
- /bin/bash
|
||||||
|
- -c
|
||||||
|
args:
|
||||||
|
- |
|
||||||
|
while : ; do
|
||||||
|
forgejo-runner register --no-interactive --token $(RUNNER_SECRET) --name $(RUNNER_NAME) --instance $(FORGEJO_INSTANCE_URL) && break ;
|
||||||
|
sleep 1 ;
|
||||||
|
done ;
|
||||||
|
forgejo-runner generate-config > /data/config.yml ;
|
||||||
|
sed -i -e "s|network: .*|network: host|" config.yml ;
|
||||||
|
sed -i -e "s|^ envs:$$| envs:\n DOCKER_HOST: tcp://localhost:2376\n DOCKER_TLS_VERIFY: 1\n DOCKER_CERT_PATH: /certs/client|" config.yml ;
|
||||||
|
sed -i -e "s|^ options:| options: -v /certs/client:/certs/client|" config.yml ;
|
||||||
|
sed -i -e "s| valid_volumes: \[\]$$| valid_volumes:\n - /certs/client|" config.yml
|
||||||
env:
|
env:
|
||||||
- name: RUNNER_NAME
|
- name: RUNNER_NAME
|
||||||
valueFrom:
|
valueFrom:
|
||||||
|
@ -51,37 +66,98 @@ spec:
|
||||||
name: runner-secret
|
name: runner-secret
|
||||||
key: token
|
key: token
|
||||||
- name: FORGEJO_INSTANCE_URL
|
- name: FORGEJO_INSTANCE_URL
|
||||||
value: http://forgejo-http.forgejo.svc.cluster.local:3000
|
value: https://my-forgejo.fr # Replace with your Forgejo instance URL
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
cpu: "0.50"
|
cpu: '0.5'
|
||||||
memory: "64Mi"
|
ephemeral-storage: 100Mi
|
||||||
|
memory: 64Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
ephemeral-storage: '0'
|
||||||
|
memory: 64Mi
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: runner-data
|
- name: runner-data
|
||||||
mountPath: /data
|
mountPath: /data
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
privileged: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
runAsNonRoot: true
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
containers:
|
containers:
|
||||||
- name: runner
|
- name: runner
|
||||||
image: code.forgejo.org/forgejo/runner:6.0.1
|
image: code.forgejo.org/forgejo/runner:6.4.0
|
||||||
command: ["sh", "-c", "while ! nc -z localhost 2376 </dev/null; do echo 'waiting for docker daemon...'; sleep 5; done; forgejo-runner daemon"]
|
command:
|
||||||
|
- /bin/bash
|
||||||
|
- -c
|
||||||
|
args:
|
||||||
|
- |
|
||||||
|
while ! nc -z localhost 2376 </dev/null ; do
|
||||||
|
echo 'waiting for docker daemon...' ;
|
||||||
|
sleep 5 ;
|
||||||
|
done ;
|
||||||
|
forgejo-runner --config config.yml daemon
|
||||||
env:
|
env:
|
||||||
- name: DOCKER_HOST
|
- name: DOCKER_HOST
|
||||||
value: tcp://localhost:2376
|
value: tcp://localhost:2376
|
||||||
- name: DOCKER_CERT_PATH
|
- name: DOCKER_CERT_PATH
|
||||||
value: /certs/client
|
value: /certs/client
|
||||||
- name: DOCKER_TLS_VERIFY
|
- name: DOCKER_TLS_VERIFY
|
||||||
value: "1"
|
value: '1'
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: '1'
|
||||||
|
ephemeral-storage: 3Gi
|
||||||
|
memory: 4Gi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
ephemeral-storage: '0'
|
||||||
|
memory: 64Mi
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: docker-certs
|
- name: docker-certs
|
||||||
mountPath: /certs
|
mountPath: /certs
|
||||||
- name: runner-data
|
- name: runner-data
|
||||||
mountPath: /data
|
mountPath: /data
|
||||||
|
- name: tmp
|
||||||
|
mountPath: /tmp
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
privileged: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
runAsNonRoot: true
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
- name: daemon
|
- name: daemon
|
||||||
image: docker:27.4.1-dind
|
image: docker.io/docker:28.3.0-dind
|
||||||
env:
|
env:
|
||||||
- name: DOCKER_TLS_CERTDIR
|
- name: DOCKER_TLS_CERTDIR
|
||||||
value: /certs
|
value: /certs
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: '1'
|
||||||
|
ephemeral-storage: 3Gi
|
||||||
|
memory: 4Gi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
ephemeral-storage: '0'
|
||||||
|
memory: 64Mi
|
||||||
securityContext:
|
securityContext:
|
||||||
privileged: true
|
privileged: true
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: docker-certs
|
- name: docker-certs
|
||||||
mountPath: /certs
|
mountPath: /certs
|
||||||
|
volumes:
|
||||||
|
- name: docker-certs
|
||||||
|
emptyDir: {}
|
||||||
|
- name: runner-data
|
||||||
|
emptyDir: {}
|
||||||
|
- name: tmp
|
||||||
|
emptyDir: {}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue