mirror of
https://github.com/actions/actions-runner-controller.git
synced 2025-12-10 11:41:27 +00:00
Compare commits
37 Commits
v0.11.3
...
actions-ru
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d37cd69e9b | ||
|
|
a2690aa5cb | ||
|
|
da020df0fd | ||
|
|
6c64ae6a01 | ||
|
|
42c7d0489d | ||
|
|
b3bef6404c | ||
|
|
1127c447c4 | ||
|
|
ace95d72ab | ||
|
|
42493d5e01 | ||
|
|
94e8c6ffbf | ||
|
|
563c79c1b9 | ||
|
|
cbb41cbd18 | ||
|
|
64a1a58acf | ||
|
|
524cf1b379 | ||
|
|
0dadddfc7d | ||
|
|
48923fec56 | ||
|
|
466b30728d | ||
|
|
c13704d7e2 | ||
|
|
fb49bbda75 | ||
|
|
8d6f77e07c | ||
|
|
dfffd3fb62 | ||
|
|
f710a54110 | ||
|
|
85c29a95f5 | ||
|
|
a2b335ad6a | ||
|
|
56c57cbf71 | ||
|
|
837563c976 | ||
|
|
df99f394b4 | ||
|
|
be25715e1e | ||
|
|
4ca825eef0 | ||
|
|
e5101554b3 | ||
|
|
ee8fb5a388 | ||
|
|
4e93879b8f | ||
|
|
6ce6737f61 | ||
|
|
4371de9733 | ||
|
|
1fd752fca2 | ||
|
|
a4061d0625 | ||
|
|
83857ba7e0 |
56
.github/workflows/build-runner.yml
vendored
56
.github/workflows/build-runner.yml
vendored
@@ -27,46 +27,38 @@ jobs:
|
|||||||
- name: actions-runner-dind
|
- name: actions-runner-dind
|
||||||
dockerfile: dindrunner.Dockerfile
|
dockerfile: dindrunner.Dockerfile
|
||||||
env:
|
env:
|
||||||
RUNNER_VERSION: 2.274.1
|
RUNNER_VERSION: 2.275.1
|
||||||
DOCKER_VERSION: 19.03.12
|
DOCKER_VERSION: 19.03.12
|
||||||
DOCKERHUB_USERNAME: ${{ github.repository_owner }}
|
DOCKERHUB_USERNAME: ${{ github.repository_owner }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
id: buildx
|
uses: docker/setup-buildx-action@v1
|
||||||
uses: crazy-max/ghaction-docker-buildx@v1
|
|
||||||
with:
|
with:
|
||||||
buildx-version: latest
|
version: latest
|
||||||
|
|
||||||
- name: Build Container Image
|
- name: Login to DockerHub
|
||||||
working-directory: runner
|
uses: docker/login-action@v1
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
|
||||||
run: |
|
|
||||||
docker buildx build \
|
|
||||||
--build-arg RUNNER_VERSION=${RUNNER_VERSION} \
|
|
||||||
--build-arg DOCKER_VERSION=${DOCKER_VERSION} \
|
|
||||||
--platform linux/amd64,linux/arm64 \
|
|
||||||
--tag ${DOCKERHUB_USERNAME}/${{ matrix.name }}:v${RUNNER_VERSION} \
|
|
||||||
--tag ${DOCKERHUB_USERNAME}/${{ matrix.name }}:latest \
|
|
||||||
-f ${{ matrix.dockerfile }} .
|
|
||||||
|
|
||||||
- name: Login to GitHub Docker Registry
|
|
||||||
run: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin
|
|
||||||
if: ${{ github.event_name == 'push' }}
|
if: ${{ github.event_name == 'push' }}
|
||||||
env:
|
with:
|
||||||
DOCKERHUB_USERNAME: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
DOCKERHUB_PASSWORD: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||||
|
|
||||||
- name: Build and Push Container Image
|
- name: Build [and Push]
|
||||||
working-directory: runner
|
uses: docker/build-push-action@v2
|
||||||
if: ${{ github.event_name == 'push' }}
|
with:
|
||||||
run: |
|
context: ./runner
|
||||||
docker buildx build \
|
file: ./runner/${{ matrix.dockerfile }}
|
||||||
--build-arg RUNNER_VERSION=${RUNNER_VERSION} \
|
platforms: linux/amd64,linux/arm64
|
||||||
--build-arg DOCKER_VERSION=${DOCKER_VERSION} \
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
--platform linux/amd64,linux/arm64 \
|
build-args: |
|
||||||
--tag ${DOCKERHUB_USERNAME}/${{ matrix.name }}:v${RUNNER_VERSION} \
|
RUNNER_VERSION=${{ env.RUNNER_VERSION }}
|
||||||
--tag ${DOCKERHUB_USERNAME}/${{ matrix.name }}:latest \
|
DOCKER_VERSION=${{ env.DOCKER_VERSION }}
|
||||||
-f ${{ matrix.dockerfile }} . --push
|
tags: |
|
||||||
|
${{ env.DOCKERHUB_USERNAME }}/${{ matrix.name }}:v${{ env.RUNNER_VERSION }}
|
||||||
|
${{ env.DOCKERHUB_USERNAME }}/${{ matrix.name }}:latest
|
||||||
|
|||||||
75
.github/workflows/on-push-lint-charts.yml
vendored
Normal file
75
.github/workflows/on-push-lint-charts.yml
vendored
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
name: Lint and Test Charts
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- 'charts/**'
|
||||||
|
- '.github/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
KUBE_SCORE_VERSION: 1.10.0
|
||||||
|
HELM_VERSION: v3.4.1
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint-test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up Helm
|
||||||
|
uses: azure/setup-helm@v1
|
||||||
|
with:
|
||||||
|
version: ${{ env.HELM_VERSION }}
|
||||||
|
|
||||||
|
- name: Set up kube-score
|
||||||
|
run: |
|
||||||
|
wget https://github.com/zegl/kube-score/releases/download/v${{ env.KUBE_SCORE_VERSION }}/kube-score_${{ env.KUBE_SCORE_VERSION }}_linux_amd64 -O kube-score
|
||||||
|
chmod 755 kube-score
|
||||||
|
|
||||||
|
- name: Kube-score generated manifests
|
||||||
|
run: helm template --values charts/.ci/values-kube-score.yaml charts/* | ./kube-score score -
|
||||||
|
--ignore-test pod-networkpolicy
|
||||||
|
--ignore-test deployment-has-poddisruptionbudget
|
||||||
|
--ignore-test deployment-has-host-podantiaffinity
|
||||||
|
--ignore-test container-security-context
|
||||||
|
--ignore-test pod-probes
|
||||||
|
--ignore-test container-image-tag
|
||||||
|
--enable-optional-test container-security-context-privileged
|
||||||
|
--enable-optional-test container-security-context-readonlyrootfilesystem
|
||||||
|
|
||||||
|
# python is a requirement for the chart-testing action below (supports yamllint among other tests)
|
||||||
|
- uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: 3.7
|
||||||
|
|
||||||
|
- name: Set up chart-testing
|
||||||
|
uses: helm/chart-testing-action@v2.0.1
|
||||||
|
|
||||||
|
- name: Run chart-testing (list-changed)
|
||||||
|
id: list-changed
|
||||||
|
run: |
|
||||||
|
changed=$(ct list-changed --config charts/.ci/ct-config.yaml)
|
||||||
|
if [[ -n "$changed" ]]; then
|
||||||
|
echo "::set-output name=changed::true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Run chart-testing (lint)
|
||||||
|
run: ct lint --config charts/.ci/ct-config.yaml
|
||||||
|
|
||||||
|
- name: Create kind cluster
|
||||||
|
uses: helm/kind-action@v1.0.0
|
||||||
|
if: steps.list-changed.outputs.changed == 'true'
|
||||||
|
|
||||||
|
# We need cert-manager already installed in the cluster because we assume the CRDs exist
|
||||||
|
- name: Install cert-manager
|
||||||
|
run: |
|
||||||
|
helm repo add jetstack https://charts.jetstack.io --force-update
|
||||||
|
helm install cert-manager jetstack/cert-manager --set installCRDs=true --wait
|
||||||
|
if: steps.list-changed.outputs.changed == 'true'
|
||||||
|
|
||||||
|
- name: Run chart-testing (install)
|
||||||
|
run: ct install --config charts/.ci/ct-config.yaml
|
||||||
101
.github/workflows/on-push-master-publish-chart.yml
vendored
Normal file
101
.github/workflows/on-push-master-publish-chart.yml
vendored
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
name: Publish helm chart
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- main # assume that the branch name may change in future
|
||||||
|
paths:
|
||||||
|
- 'charts/**'
|
||||||
|
- '.github/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
KUBE_SCORE_VERSION: 1.10.0
|
||||||
|
HELM_VERSION: v3.4.1
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint-chart:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up Helm
|
||||||
|
uses: azure/setup-helm@v1
|
||||||
|
with:
|
||||||
|
version: ${{ env.HELM_VERSION }}
|
||||||
|
|
||||||
|
- name: Set up kube-score
|
||||||
|
run: |
|
||||||
|
wget https://github.com/zegl/kube-score/releases/download/v${{ env.KUBE_SCORE_VERSION }}/kube-score_${{ env.KUBE_SCORE_VERSION }}_linux_amd64 -O kube-score
|
||||||
|
chmod 755 kube-score
|
||||||
|
|
||||||
|
- name: Kube-score generated manifests
|
||||||
|
run: helm template --values charts/.ci/values-kube-score.yaml charts/* | ./kube-score score -
|
||||||
|
--ignore-test pod-networkpolicy
|
||||||
|
--ignore-test deployment-has-poddisruptionbudget
|
||||||
|
--ignore-test deployment-has-host-podantiaffinity
|
||||||
|
--ignore-test container-security-context
|
||||||
|
--ignore-test pod-probes
|
||||||
|
--ignore-test container-image-tag
|
||||||
|
--enable-optional-test container-security-context-privileged
|
||||||
|
--enable-optional-test container-security-context-readonlyrootfilesystem
|
||||||
|
|
||||||
|
# python is a requirement for the chart-testing action below (supports yamllint among other tests)
|
||||||
|
- uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: 3.7
|
||||||
|
|
||||||
|
- name: Set up chart-testing
|
||||||
|
uses: helm/chart-testing-action@v2.0.1
|
||||||
|
|
||||||
|
- name: Run chart-testing (list-changed)
|
||||||
|
id: list-changed
|
||||||
|
run: |
|
||||||
|
changed=$(ct list-changed --config charts/.ci/ct-config.yaml)
|
||||||
|
if [[ -n "$changed" ]]; then
|
||||||
|
echo "::set-output name=changed::true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Run chart-testing (lint)
|
||||||
|
run: ct lint --config charts/.ci/ct-config.yaml
|
||||||
|
|
||||||
|
- name: Create kind cluster
|
||||||
|
uses: helm/kind-action@v1.0.0
|
||||||
|
if: steps.list-changed.outputs.changed == 'true'
|
||||||
|
|
||||||
|
# We need cert-manager already installed in the cluster because we assume the CRDs exist
|
||||||
|
- name: Install cert-manager
|
||||||
|
run: |
|
||||||
|
helm repo add jetstack https://charts.jetstack.io --force-update
|
||||||
|
helm install cert-manager jetstack/cert-manager --set installCRDs=true --wait
|
||||||
|
if: steps.list-changed.outputs.changed == 'true'
|
||||||
|
|
||||||
|
- name: Run chart-testing (install)
|
||||||
|
run: ct install --config charts/.ci/ct-config.yaml
|
||||||
|
if: steps.list-changed.outputs.changed == 'true'
|
||||||
|
|
||||||
|
publish-chart:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: lint-chart
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Configure Git
|
||||||
|
run: |
|
||||||
|
git config user.name "$GITHUB_ACTOR"
|
||||||
|
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
||||||
|
|
||||||
|
- name: Run chart-releaser
|
||||||
|
uses: helm/chart-releaser-action@v1.1.0
|
||||||
|
env:
|
||||||
|
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
|
|
||||||
37
.github/workflows/release.yml
vendored
37
.github/workflows/release.yml
vendored
@@ -6,6 +6,8 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: Release
|
name: Release
|
||||||
|
env:
|
||||||
|
DOCKERHUB_USERNAME: ${{ github.repository_owner }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@@ -22,30 +24,33 @@ jobs:
|
|||||||
sudo mv ghr_v0.13.0_linux_amd64/ghr /usr/local/bin
|
sudo mv ghr_v0.13.0_linux_amd64/ghr /usr/local/bin
|
||||||
|
|
||||||
- name: Set version
|
- name: Set version
|
||||||
run: echo "::set-env name=VERSION::$(cat ${GITHUB_EVENT_PATH} | jq -r '.release.tag_name')"
|
run: echo "VERSION=$(cat ${GITHUB_EVENT_PATH} | jq -r '.release.tag_name')" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: make github-release
|
run: make github-release
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: crazy-max/ghaction-docker-buildx@v1
|
uses: docker/setup-buildx-action@v1
|
||||||
with:
|
with:
|
||||||
buildx-version: latest
|
version: latest
|
||||||
|
|
||||||
- name: Login to GitHub Docker Registry
|
- name: Login to DockerHub
|
||||||
run: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin
|
uses: docker/login-action@v1
|
||||||
env:
|
with:
|
||||||
DOCKERHUB_USERNAME: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
DOCKERHUB_PASSWORD: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and Push
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
file: Dockerfile
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: ${{ env.DOCKERHUB_USERNAME }}/actions-runner-controller:${{ env.VERSION }}
|
||||||
|
|
||||||
- name: Build Container Image
|
|
||||||
env:
|
|
||||||
DOCKERHUB_USERNAME: ${{ github.repository_owner }}
|
|
||||||
run: |
|
|
||||||
docker buildx build \
|
|
||||||
--platform linux/amd64,linux/arm64 \
|
|
||||||
--tag ${DOCKERHUB_USERNAME}/actions-runner-controller:${{ env.VERSION }} \
|
|
||||||
-f Dockerfile . --push
|
|
||||||
|
|||||||
35
.github/workflows/wip.yml
vendored
35
.github/workflows/wip.yml
vendored
@@ -9,27 +9,32 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: release-latest
|
name: release-latest
|
||||||
|
env:
|
||||||
|
DOCKERHUB_USERNAME: ${{ github.repository_owner }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: crazy-max/ghaction-docker-buildx@v1
|
uses: docker/setup-buildx-action@v1
|
||||||
with:
|
with:
|
||||||
buildx-version: latest
|
version: latest
|
||||||
|
|
||||||
- name: Login to GitHub Docker Registry
|
- name: Login to DockerHub
|
||||||
run: echo "${DOCKERHUB_PASSWORD}" | docker login -u "${DOCKERHUB_USERNAME}" --password-stdin
|
uses: docker/login-action@v1
|
||||||
env:
|
with:
|
||||||
DOCKERHUB_USERNAME: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
DOCKERHUB_PASSWORD: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and Push
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
file: Dockerfile
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: ${{ env.DOCKERHUB_USERNAME }}/actions-runner-controller:latest
|
||||||
|
|
||||||
- name: Build Container Image
|
|
||||||
env:
|
|
||||||
DOCKERHUB_USERNAME: ${{ github.repository_owner }}
|
|
||||||
run: |
|
|
||||||
docker buildx build \
|
|
||||||
--platform linux/amd64,linux/arm64 \
|
|
||||||
--tag ${DOCKERHUB_USERNAME}/actions-runner-controller:latest \
|
|
||||||
-f Dockerfile . --push
|
|
||||||
|
|||||||
22
Makefile
22
Makefile
@@ -121,21 +121,27 @@ release: manifests
|
|||||||
mkdir -p release
|
mkdir -p release
|
||||||
kustomize build config/default > release/actions-runner-controller.yaml
|
kustomize build config/default > release/actions-runner-controller.yaml
|
||||||
|
|
||||||
.PHONY: acceptance
|
.PHONY: release/clean
|
||||||
acceptance: release
|
release/clean:
|
||||||
ACCEPTANCE_TEST_SECRET_TYPE=token make acceptance/setup acceptance/tests acceptance/teardown
|
rm -rf release
|
||||||
ACCEPTANCE_TEST_SECRET_TYPE=app make acceptance/setup acceptance/tests acceptance/teardown
|
|
||||||
ACCEPTANCE_TEST_DEPLOYMENT_TOOL=helm ACCEPTANCE_TEST_SECRET_TYPE=token make acceptance/setup acceptance/tests acceptance/teardown
|
|
||||||
ACCEPTANCE_TEST_DEPLOYMENT_TOOL=helm ACCEPTANCE_TEST_SECRET_TYPE=app make acceptance/setup acceptance/tests acceptance/teardown
|
|
||||||
|
|
||||||
acceptance/setup:
|
.PHONY: acceptance
|
||||||
|
acceptance: release/clean docker-build docker-push release
|
||||||
|
ACCEPTANCE_TEST_SECRET_TYPE=token make acceptance/kind acceptance/setup acceptance/tests acceptance/teardown
|
||||||
|
ACCEPTANCE_TEST_SECRET_TYPE=app make acceptance/kind acceptance/setup acceptance/tests acceptance/teardown
|
||||||
|
ACCEPTANCE_TEST_DEPLOYMENT_TOOL=helm ACCEPTANCE_TEST_SECRET_TYPE=token make acceptance/kind acceptance/setup acceptance/tests acceptance/teardown
|
||||||
|
ACCEPTANCE_TEST_DEPLOYMENT_TOOL=helm ACCEPTANCE_TEST_SECRET_TYPE=app make acceptance/kind acceptance/setup acceptance/tests acceptance/teardown
|
||||||
|
|
||||||
|
acceptance/kind:
|
||||||
kind create cluster --name acceptance
|
kind create cluster --name acceptance
|
||||||
kubectl cluster-info --context kind-acceptance
|
kubectl cluster-info --context kind-acceptance
|
||||||
|
|
||||||
|
acceptance/setup:
|
||||||
kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.0.4/cert-manager.yaml #kubectl create namespace actions-runner-system
|
kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.0.4/cert-manager.yaml #kubectl create namespace actions-runner-system
|
||||||
kubectl -n cert-manager wait deploy/cert-manager-cainjector --for condition=available --timeout 60s
|
kubectl -n cert-manager wait deploy/cert-manager-cainjector --for condition=available --timeout 60s
|
||||||
kubectl -n cert-manager wait deploy/cert-manager-webhook --for condition=available --timeout 60s
|
kubectl -n cert-manager wait deploy/cert-manager-webhook --for condition=available --timeout 60s
|
||||||
kubectl -n cert-manager wait deploy/cert-manager --for condition=available --timeout 60s
|
kubectl -n cert-manager wait deploy/cert-manager --for condition=available --timeout 60s
|
||||||
kubectl create namespace actions-runner-system
|
kubectl create namespace actions-runner-system || true
|
||||||
# Adhocly wait for some time until cert-manager's admission webhook gets ready
|
# Adhocly wait for some time until cert-manager's admission webhook gets ready
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
|
|||||||
96
README.md
96
README.md
@@ -14,10 +14,20 @@ actions-runner-controller uses [cert-manager](https://cert-manager.io/docs/insta
|
|||||||
|
|
||||||
- [Installing cert-manager on Kubernetes](https://cert-manager.io/docs/installation/kubernetes/)
|
- [Installing cert-manager on Kubernetes](https://cert-manager.io/docs/installation/kubernetes/)
|
||||||
|
|
||||||
Install the custom resource and actions-runner-controller itself. This will create actions-runner-system namespace in your Kubernetes and deploy the required resources.
|
Install the custom resource and actions-runner-controller with `kubectl` or `helm`. This will create actions-runner-system namespace in your Kubernetes and deploy the required resources.
|
||||||
|
|
||||||
|
`kubectl`:
|
||||||
|
|
||||||
```
|
```
|
||||||
kubectl apply -f https://github.com/summerwind/actions-runner-controller/releases/latest/download/actions-runner-controller.yaml
|
# REPLACE "v0.16.1" with the latest release
|
||||||
|
kubectl apply -f https://github.com/summerwind/actions-runner-controller/releases/download/v0.16.1/actions-runner-controller.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
`helm`:
|
||||||
|
|
||||||
|
```
|
||||||
|
helm repo add actions-runner-controller https://summerwind.github.io/actions-runner-controller
|
||||||
|
helm upgrade --install -n actions-runner-system actions-runner-controller/actions-runner-controller
|
||||||
```
|
```
|
||||||
|
|
||||||
### Github Enterprise support
|
### Github Enterprise support
|
||||||
@@ -25,7 +35,7 @@ kubectl apply -f https://github.com/summerwind/actions-runner-controller/release
|
|||||||
If you use either Github Enterprise Cloud or Server (and have recent enought version supporting Actions), you can use **actions-runner-controller** with those, too. Authentication works same way as with public Github (repo and organization level).
|
If you use either Github Enterprise Cloud or Server (and have recent enought version supporting Actions), you can use **actions-runner-controller** with those, too. Authentication works same way as with public Github (repo and organization level).
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
kubectl set env deploy controller-manager -c manager GITHUB_ENTERPRISE_URL=<GHEC/S URL>
|
kubectl set env deploy controller-manager -c manager GITHUB_ENTERPRISE_URL=<GHEC/S URL> --namespace actions-runner-system
|
||||||
```
|
```
|
||||||
|
|
||||||
[Enterprise level](https://docs.github.com/en/enterprise-server@2.22/actions/hosting-your-own-runners/adding-self-hosted-runners#adding-a-self-hosted-runner-to-an-enterprise) runners are not working yet as there's no API definition for those.
|
[Enterprise level](https://docs.github.com/en/enterprise-server@2.22/actions/hosting-your-own-runners/adding-self-hosted-runners#adding-a-self-hosted-runner-to-an-enterprise) runners are not working yet as there's no API definition for those.
|
||||||
@@ -267,6 +277,28 @@ spec:
|
|||||||
- summerwind/actions-runner-controller
|
- summerwind/actions-runner-controller
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you do not want to manage an explicit list of repositories to scale, an alternate autoscaling scheme that can be applied is the PercentageRunnersBusy scheme. The number of desired pods are evaulated by checking how many runners are currently busy and applying a scaleup or scale down factor if certain thresholds are met. By setting the metric type to PercentageRunnersBusy, the HorizontalRunnerAutoscaler will query github for the number of busy runners which live in the RunnerDeployment namespace. Scaleup and scaledown thresholds are the percentage of busy runners at which the number of desired runners are re-evaluated. Scaleup and scaledown factors are the multiplicative factor applied to the current number of runners used to calculate the number of desired runners. This scheme is also especially useful if you want multiple controllers in various clusters, each responsible for scaling their own runner pods per namespace.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
|
kind: HorizontalRunnerAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: example-runner-deployment-autoscaler
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
name: example-runner-deployment
|
||||||
|
minReplicas: 1
|
||||||
|
maxReplicas: 3
|
||||||
|
scaleDownDelaySecondsAfterScaleOut: 60
|
||||||
|
metrics:
|
||||||
|
- type: PercentageRunnersBusy
|
||||||
|
scaleUpThreshold: '0.75'
|
||||||
|
scaleDownThreshold: '0.3'
|
||||||
|
scaleUpFactor: '1.4'
|
||||||
|
scaleDownFactor: '0.7'
|
||||||
|
```
|
||||||
|
|
||||||
## Runner with DinD
|
## Runner with DinD
|
||||||
|
|
||||||
When using default runner, runner pod starts up 2 containers: runner and DinD (Docker-in-Docker). This might create issues if there's `LimitRange` set to namespace.
|
When using default runner, runner pod starts up 2 containers: runner and DinD (Docker-in-Docker). This might create issues if there's `LimitRange` set to namespace.
|
||||||
@@ -321,6 +353,8 @@ spec:
|
|||||||
requests:
|
requests:
|
||||||
cpu: "2.0"
|
cpu: "2.0"
|
||||||
memory: "4Gi"
|
memory: "4Gi"
|
||||||
|
# If set to false, there are no privileged container and you cannot use docker.
|
||||||
|
dockerEnabled: false
|
||||||
# If set to true, runner pod container only 1 container that's expected to be able to run docker, too.
|
# If set to true, runner pod container only 1 container that's expected to be able to run docker, too.
|
||||||
# image summerwind/actions-runner-dind or custom one should be used with true -value
|
# image summerwind/actions-runner-dind or custom one should be used with true -value
|
||||||
dockerdWithinRunnerContainer: false
|
dockerdWithinRunnerContainer: false
|
||||||
@@ -340,6 +374,10 @@ spec:
|
|||||||
value: abcd1234
|
value: abcd1234
|
||||||
securityContext:
|
securityContext:
|
||||||
runAsUser: 0
|
runAsUser: 0
|
||||||
|
# if workDir is not specified, the default working directory is /runner/_work
|
||||||
|
# this setting allows you to customize the working directory location
|
||||||
|
# for example, the below setting is the same as on the ubuntu-18.04 image
|
||||||
|
workDir: /home/runner/work
|
||||||
```
|
```
|
||||||
|
|
||||||
## Runner labels
|
## Runner labels
|
||||||
@@ -381,7 +419,7 @@ Note that if you specify `self-hosted` in your workflow, then this will run your
|
|||||||
|
|
||||||
## Runner Groups
|
## Runner Groups
|
||||||
|
|
||||||
Runner groups can be used to limit which repositories are able to use the GitHub Runner at an Organisation level.
|
Runner groups can be used to limit which repositories are able to use the GitHub Runner at an Organisation level. Runner groups have to be [created in GitHub first](https://docs.github.com/en/actions/hosting-your-own-runners/managing-access-to-self-hosted-runners-using-groups) before they can be referenced.
|
||||||
|
|
||||||
To add the runner to the group `NewGroup`, specify the group in your `Runner` or `RunnerDeployment` spec.
|
To add the runner to the group `NewGroup`, specify the group in your `Runner` or `RunnerDeployment` spec.
|
||||||
|
|
||||||
@@ -398,6 +436,32 @@ spec:
|
|||||||
group: NewGroup
|
group: NewGroup
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Using EKS IAM role for service accounts
|
||||||
|
|
||||||
|
`actions-runner-controller` v0.15.0 or later has support for EKS IAM role for service accounts.
|
||||||
|
|
||||||
|
As similar as for regular pods and deployments, you firstly need an existing service account with the IAM role associated.
|
||||||
|
Create one using e.g. `eksctl`. You can refer to [the EKS documentation](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) for more details.
|
||||||
|
|
||||||
|
Once you set up the service account, all you need is to add `serviceAccountName` and `fsGroup` to any pods that uses
|
||||||
|
the IAM-role enabled service account.
|
||||||
|
|
||||||
|
For `RunnerDeployment`, you can set those two fields under the runner spec at `RunnerDeployment.Spec.Template`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
|
kind: RunnerDeployment
|
||||||
|
metadata:
|
||||||
|
name: example-runnerdeploy
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
repository: USER/REO
|
||||||
|
serviceAccountName: my-service-account
|
||||||
|
securityContext:
|
||||||
|
fsGroup: 1447
|
||||||
|
```
|
||||||
|
|
||||||
## Software installed in the runner image
|
## Software installed in the runner image
|
||||||
|
|
||||||
The GitHub hosted runners include a large amount of pre-installed software packages. For Ubuntu 18.04, this list can be found at <https://github.com/actions/virtual-environments/blob/master/images/linux/Ubuntu1804-README.md>
|
The GitHub hosted runners include a large amount of pre-installed software packages. For Ubuntu 18.04, this list can be found at <https://github.com/actions/virtual-environments/blob/master/images/linux/Ubuntu1804-README.md>
|
||||||
@@ -414,11 +478,11 @@ The virtual environments from GitHub contain a lot more software packages (diffe
|
|||||||
If there is a need to include packages in the runner image for which there is no setup action, then this can be achieved by building a custom container image for the runner. The easiest way is to start with the `summerwind/actions-runner` image and installing the extra dependencies directly in the docker image:
|
If there is a need to include packages in the runner image for which there is no setup action, then this can be achieved by building a custom container image for the runner. The easiest way is to start with the `summerwind/actions-runner` image and installing the extra dependencies directly in the docker image:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
FROM summerwind/actions-runner:v2.169.1
|
FROM summerwind/actions-runner:latest
|
||||||
|
|
||||||
RUN sudo apt update -y \
|
RUN sudo apt update -y \
|
||||||
&& apt install YOUR_PACKAGE
|
&& sudo apt install YOUR_PACKAGE
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& sudo rm -rf /var/lib/apt/lists/*
|
||||||
```
|
```
|
||||||
|
|
||||||
You can then configure the runner to use a custom docker image by configuring the `image` field of a `Runner` or `RunnerDeployment`:
|
You can then configure the runner to use a custom docker image by configuring the `image` field of a `Runner` or `RunnerDeployment`:
|
||||||
@@ -452,7 +516,10 @@ If you'd like to modify the controller to fork or contribute, I'd suggest using
|
|||||||
the acceptance test:
|
the acceptance test:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
NAME=$DOCKER_USER/actions-runner-controller VERSION=dev \
|
# This sets `VERSION` envvar to some appropriate value
|
||||||
|
. hack/make-env.sh
|
||||||
|
|
||||||
|
NAME=$DOCKER_USER/actions-runner-controller \
|
||||||
GITHUB_TOKEN=*** \
|
GITHUB_TOKEN=*** \
|
||||||
APP_ID=*** \
|
APP_ID=*** \
|
||||||
PRIVATE_KEY_FILE_PATH=path/to/pem/file \
|
PRIVATE_KEY_FILE_PATH=path/to/pem/file \
|
||||||
@@ -468,6 +535,19 @@ The test creates a one-off `kind` cluster, deploys `cert-manager` and `actions-r
|
|||||||
creates a `RunnerDeployment` custom resource for a public Git repository to confirm that the
|
creates a `RunnerDeployment` custom resource for a public Git repository to confirm that the
|
||||||
controller is able to bring up a runner pod with the actions runner registration token installed.
|
controller is able to bring up a runner pod with the actions runner registration token installed.
|
||||||
|
|
||||||
|
If you prefer to test in a non-kind cluster, you can instead run:
|
||||||
|
|
||||||
|
```shell script
|
||||||
|
KUBECONFIG=path/to/kubeconfig \
|
||||||
|
NAME=$DOCKER_USER/actions-runner-controller \
|
||||||
|
GITHUB_TOKEN=*** \
|
||||||
|
APP_ID=*** \
|
||||||
|
PRIVATE_KEY_FILE_PATH=path/to/pem/file \
|
||||||
|
INSTALLATION_ID=*** \
|
||||||
|
ACCEPTANCE_TEST_SECRET_TYPE=token \
|
||||||
|
make docker-build docker-push \
|
||||||
|
acceptance/setup acceptance/tests
|
||||||
|
```
|
||||||
# Alternatives
|
# Alternatives
|
||||||
|
|
||||||
The following is a list of alternative solutions that may better fit you depending on your use-case:
|
The following is a list of alternative solutions that may better fit you depending on your use-case:
|
||||||
|
|||||||
@@ -24,6 +24,6 @@ echo Found pod ${pod_name}.
|
|||||||
|
|
||||||
echo Waiting for pod ${runner_name} to become ready... 1>&2
|
echo Waiting for pod ${runner_name} to become ready... 1>&2
|
||||||
|
|
||||||
kubectl wait pod/${runner_name} --for condition=ready --timeout 120s
|
kubectl wait pod/${runner_name} --for condition=ready --timeout 180s
|
||||||
|
|
||||||
echo All tests passed. 1>&2
|
echo All tests passed. 1>&2
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ else
|
|||||||
kubectl apply \
|
kubectl apply \
|
||||||
-n actions-runner-system \
|
-n actions-runner-system \
|
||||||
-f release/actions-runner-controller.yaml
|
-f release/actions-runner-controller.yaml
|
||||||
kubectl -n actions-runner-system wait deploy/controller-manager --for condition=available
|
kubectl -n actions-runner-system wait deploy/controller-manager --for condition=available --timeout 60s
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Adhocly wait for some time until actions-runner-controller's admission webhook gets ready
|
# Adhocly wait for some time until actions-runner-controller's admission webhook gets ready
|
||||||
|
|||||||
@@ -56,6 +56,26 @@ type MetricSpec struct {
|
|||||||
// For example, a repository name is the REPO part of `github.com/USER/REPO`.
|
// For example, a repository name is the REPO part of `github.com/USER/REPO`.
|
||||||
// +optional
|
// +optional
|
||||||
RepositoryNames []string `json:"repositoryNames,omitempty"`
|
RepositoryNames []string `json:"repositoryNames,omitempty"`
|
||||||
|
|
||||||
|
// ScaleUpThreshold is the percentage of busy runners greater than which will
|
||||||
|
// trigger the hpa to scale runners up.
|
||||||
|
// +optional
|
||||||
|
ScaleUpThreshold string `json:"scaleUpThreshold,omitempty"`
|
||||||
|
|
||||||
|
// ScaleDownThreshold is the percentage of busy runners less than which will
|
||||||
|
// trigger the hpa to scale the runners down.
|
||||||
|
// +optional
|
||||||
|
ScaleDownThreshold string `json:"scaleDownThreshold,omitempty"`
|
||||||
|
|
||||||
|
// ScaleUpFactor is the multiplicative factor applied to the current number of runners used
|
||||||
|
// to determine how many pods should be added.
|
||||||
|
// +optional
|
||||||
|
ScaleUpFactor string `json:"scaleUpFactor,omitempty"`
|
||||||
|
|
||||||
|
// ScaleDownFactor is the multiplicative factor applied to the current number of runners used
|
||||||
|
// to determine how many pods should be removed.
|
||||||
|
// +optional
|
||||||
|
ScaleDownFactor string `json:"scaleDownFactor,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type HorizontalRunnerAutoscalerStatus struct {
|
type HorizontalRunnerAutoscalerStatus struct {
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ type RunnerSpec struct {
|
|||||||
|
|
||||||
// +optional
|
// +optional
|
||||||
Volumes []corev1.Volume `json:"volumes,omitempty"`
|
Volumes []corev1.Volume `json:"volumes,omitempty"`
|
||||||
|
// +optional
|
||||||
|
WorkDir string `json:"workDir,omitempty"`
|
||||||
|
|
||||||
// +optional
|
// +optional
|
||||||
InitContainers []corev1.Container `json:"initContainers,omitempty"`
|
InitContainers []corev1.Container `json:"initContainers,omitempty"`
|
||||||
@@ -84,6 +86,8 @@ type RunnerSpec struct {
|
|||||||
TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"`
|
TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"`
|
||||||
// +optional
|
// +optional
|
||||||
DockerdWithinRunnerContainer *bool `json:"dockerdWithinRunnerContainer,omitempty"`
|
DockerdWithinRunnerContainer *bool `json:"dockerdWithinRunnerContainer,omitempty"`
|
||||||
|
// +optional
|
||||||
|
DockerEnabled *bool `json:"dockerEnabled,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateRepository validates repository field.
|
// ValidateRepository validates repository field.
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
AutoscalingMetricTypeTotalNumberOfQueuedAndInProgressWorkflowRuns = "TotalNumberOfQueuedAndInProgressWorkflowRuns"
|
AutoscalingMetricTypeTotalNumberOfQueuedAndInProgressWorkflowRuns = "TotalNumberOfQueuedAndInProgressWorkflowRuns"
|
||||||
|
AutoscalingMetricTypePercentageRunnersBusy = "PercentageRunnersBusy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RunnerReplicaSetSpec defines the desired state of RunnerDeployment
|
// RunnerReplicaSetSpec defines the desired state of RunnerDeployment
|
||||||
|
|||||||
@@ -530,6 +530,11 @@ func (in *RunnerSpec) DeepCopyInto(out *RunnerSpec) {
|
|||||||
*out = new(bool)
|
*out = new(bool)
|
||||||
**out = **in
|
**out = **in
|
||||||
}
|
}
|
||||||
|
if in.DockerEnabled != nil {
|
||||||
|
in, out := &in.DockerEnabled, &out.DockerEnabled
|
||||||
|
*out = new(bool)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerSpec.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerSpec.
|
||||||
|
|||||||
4
charts/.ci/ct-config.yaml
Normal file
4
charts/.ci/ct-config.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# This file defines the config for "ct" (chart tester) used by the helm linting GitHub workflow
|
||||||
|
lint-conf: charts/.ci/lint-config.yaml
|
||||||
|
chart-repos:
|
||||||
|
- jetstack=https://charts.jetstack.io
|
||||||
6
charts/.ci/lint-config.yaml
Normal file
6
charts/.ci/lint-config.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
rules:
|
||||||
|
# One blank line is OK
|
||||||
|
empty-lines:
|
||||||
|
max-start: 1
|
||||||
|
max-end: 1
|
||||||
|
max: 1
|
||||||
3
charts/.ci/scripts/local-ct-lint.sh
Executable file
3
charts/.ci/scripts/local-ct-lint.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
docker run --rm -it -w /repo -v $(pwd):/repo quay.io/helmpack/chart-testing ct lint --all --config charts/.ci/ct-config.yaml
|
||||||
15
charts/.ci/scripts/local-kube-score.sh
Executable file
15
charts/.ci/scripts/local-kube-score.sh
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
|
||||||
|
for chart in `ls charts`;
|
||||||
|
do
|
||||||
|
helm template --values charts/$chart/ci/ci-values.yaml charts/$chart | kube-score score - \
|
||||||
|
--ignore-test pod-networkpolicy \
|
||||||
|
--ignore-test deployment-has-poddisruptionbudget \
|
||||||
|
--ignore-test deployment-has-host-podantiaffinity \
|
||||||
|
--ignore-test pod-probes \
|
||||||
|
--ignore-test container-image-tag \
|
||||||
|
--enable-optional-test container-security-context-privileged \
|
||||||
|
--enable-optional-test container-security-context-readonlyrootfilesystem \
|
||||||
|
--ignore-test container-security-context
|
||||||
|
done
|
||||||
@@ -15,9 +15,22 @@ type: application
|
|||||||
# This is the chart version. This version number should be incremented each time you make changes
|
# This is the chart version. This version number should be incremented each time you make changes
|
||||||
# to the chart and its templates, including the app version.
|
# to the chart and its templates, including the app version.
|
||||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||||
version: 0.1.0
|
version: 0.2.1
|
||||||
|
|
||||||
# This is the version number of the application being deployed. This version number should be
|
# This is the version number of the application being deployed. This version number should be
|
||||||
# incremented each time you make changes to the application. Versions are not expected to
|
# incremented each time you make changes to the application. Versions are not expected to
|
||||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||||
appVersion: 0.11.2
|
appVersion: 0.16.1
|
||||||
|
|
||||||
|
home: https://github.com/summerwind/actions-runner-controller
|
||||||
|
|
||||||
|
sources:
|
||||||
|
- https://github.com/summerwind/actions-runner-controller
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- name: summerwind
|
||||||
|
email: contact@summerwind.jp
|
||||||
|
url: https://github.com/summerwind
|
||||||
|
- name: funkypenguin
|
||||||
|
email: davidy@funkypenguin.co.nz
|
||||||
|
url: https://www.funkypenguin.co.nz
|
||||||
|
|||||||
27
charts/actions-runner-controller/ci/ci-values.yaml
Normal file
27
charts/actions-runner-controller/ci/ci-values.yaml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# This file sets some opinionated values for kube-score to use
|
||||||
|
# when parsing the chart
|
||||||
|
image:
|
||||||
|
pullPolicy: Always
|
||||||
|
|
||||||
|
podSecurityContext:
|
||||||
|
fsGroup: 2000
|
||||||
|
|
||||||
|
securityContext:
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 2000
|
||||||
|
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
|
||||||
|
# Set the following to true to create a dummy secret, allowing the manager pod to start
|
||||||
|
# This is only useful in CI
|
||||||
|
createDummySecret: true
|
||||||
@@ -64,6 +64,24 @@ spec:
|
|||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
scaleDownFactor:
|
||||||
|
description: ScaleDownFactor is the multiplicative factor applied
|
||||||
|
to the current number of runners used to determine how many
|
||||||
|
pods should be removed.
|
||||||
|
type: string
|
||||||
|
scaleDownThreshold:
|
||||||
|
description: ScaleDownThreshold is the percentage of busy runners
|
||||||
|
less than which will trigger the hpa to scale the runners down.
|
||||||
|
type: string
|
||||||
|
scaleUpFactor:
|
||||||
|
description: ScaleUpFactor is the multiplicative factor applied
|
||||||
|
to the current number of runners used to determine how many
|
||||||
|
pods should be added.
|
||||||
|
type: string
|
||||||
|
scaleUpThreshold:
|
||||||
|
description: ScaleUpThreshold is the percentage of busy runners
|
||||||
|
greater than which will trigger the hpa to scale runners up.
|
||||||
|
type: string
|
||||||
type:
|
type:
|
||||||
description: Type is the type of metric to be used for autoscaling.
|
description: Type is the type of metric to be used for autoscaling.
|
||||||
The only supported Type is TotalNumberOfQueuedAndInProgressWorkflowRuns
|
The only supported Type is TotalNumberOfQueuedAndInProgressWorkflowRuns
|
||||||
|
|||||||
@@ -400,6 +400,8 @@ spec:
|
|||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
dockerEnabled:
|
||||||
|
type: boolean
|
||||||
dockerdContainerResources:
|
dockerdContainerResources:
|
||||||
description: ResourceRequirements describes the compute resource requirements.
|
description: ResourceRequirements describes the compute resource requirements.
|
||||||
properties:
|
properties:
|
||||||
@@ -1531,6 +1533,8 @@ spec:
|
|||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
workDir:
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
|
|||||||
@@ -400,6 +400,8 @@ spec:
|
|||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
dockerEnabled:
|
||||||
|
type: boolean
|
||||||
dockerdContainerResources:
|
dockerdContainerResources:
|
||||||
description: ResourceRequirements describes the compute resource requirements.
|
description: ResourceRequirements describes the compute resource requirements.
|
||||||
properties:
|
properties:
|
||||||
@@ -1531,6 +1533,8 @@ spec:
|
|||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
workDir:
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
|
|||||||
@@ -393,6 +393,8 @@ spec:
|
|||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
dockerEnabled:
|
||||||
|
type: boolean
|
||||||
dockerdContainerResources:
|
dockerdContainerResources:
|
||||||
description: ResourceRequirements describes the compute resource requirements.
|
description: ResourceRequirements describes the compute resource requirements.
|
||||||
properties:
|
properties:
|
||||||
@@ -1524,6 +1526,8 @@ spec:
|
|||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
workDir:
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
status:
|
status:
|
||||||
description: RunnerStatus defines the observed state of Runner
|
description: RunnerStatus defines the observed state of Runner
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ helm.sh/chart: {{ include "actions-runner-controller.chart" . }}
|
|||||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- range $k, $v := .Values.labels }}
|
||||||
|
{{ $k }}: {{ $v }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{/*
|
{{/*
|
||||||
@@ -86,7 +89,7 @@ Create the name of the service account to use
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{- define "actions-runner-controller.authProxyServiceName" -}}
|
{{- define "actions-runner-controller.authProxyServiceName" -}}
|
||||||
{{- include "actions-runner-controller.fullname" . }}-controller-manager-metrics-service
|
{{- include "actions-runner-controller.fullname" . }}-metrics-service
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{- define "actions-runner-controller.selfsignedIssuerName" -}}
|
{{- define "actions-runner-controller.selfsignedIssuerName" -}}
|
||||||
|
|||||||
10
charts/actions-runner-controller/templates/ci-secret.yaml
Normal file
10
charts/actions-runner-controller/templates/ci-secret.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# This template only exists to facilitate CI testing of the chart, since
|
||||||
|
# a secret is expected to be found in the namespace by the controller manager
|
||||||
|
{{ if .Values.createDummySecret -}}
|
||||||
|
apiVersion: v1
|
||||||
|
data:
|
||||||
|
github_token: dGVzdA==
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: controller-manager
|
||||||
|
{{- end }}
|
||||||
@@ -25,11 +25,15 @@ spec:
|
|||||||
serviceAccountName: {{ include "actions-runner-controller.serviceAccountName" . }}
|
serviceAccountName: {{ include "actions-runner-controller.serviceAccountName" . }}
|
||||||
securityContext:
|
securityContext:
|
||||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||||
|
{{- with .Values.priorityClassName }}
|
||||||
|
priorityClassName: "{{ . }}"
|
||||||
|
{{- end }}
|
||||||
containers:
|
containers:
|
||||||
- args:
|
- args:
|
||||||
- "--metrics-addr=127.0.0.1:8080"
|
- "--metrics-addr=127.0.0.1:8080"
|
||||||
- "--enable-leader-election"
|
- "--enable-leader-election"
|
||||||
- "--sync-period={{ .Values.syncPeriod }}"
|
- "--sync-period={{ .Values.syncPeriod }}"
|
||||||
|
- "--docker-image={{ .Values.image.dindSidecarRepositoryAndTag }}"
|
||||||
command:
|
command:
|
||||||
- "/manager"
|
- "/manager"
|
||||||
env:
|
env:
|
||||||
@@ -53,6 +57,10 @@ spec:
|
|||||||
optional: true
|
optional: true
|
||||||
- name: GITHUB_APP_PRIVATE_KEY
|
- name: GITHUB_APP_PRIVATE_KEY
|
||||||
value: /etc/actions-runner-controller/github_app_private_key
|
value: /etc/actions-runner-controller/github_app_private_key
|
||||||
|
{{- range $key, $val := .Values.env }}
|
||||||
|
- name: {{ $key }}
|
||||||
|
value: {{ $val | quote }}
|
||||||
|
{{- end }}
|
||||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default (cat "v" .Chart.AppVersion | replace " " "") }}"
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default (cat "v" .Chart.AppVersion | replace " " "") }}"
|
||||||
name: manager
|
name: manager
|
||||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
@@ -62,10 +70,14 @@ spec:
|
|||||||
protocol: TCP
|
protocol: TCP
|
||||||
resources:
|
resources:
|
||||||
{{- toYaml .Values.resources | nindent 12 }}
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- mountPath: "/etc/actions-runner-controller"
|
- mountPath: "/etc/actions-runner-controller"
|
||||||
name: controller-manager
|
name: controller-manager
|
||||||
readOnly: true
|
readOnly: true
|
||||||
|
- mountPath: /tmp
|
||||||
|
name: tmp
|
||||||
- mountPath: /tmp/k8s-webhook-server/serving-certs
|
- mountPath: /tmp/k8s-webhook-server/serving-certs
|
||||||
name: cert
|
name: cert
|
||||||
readOnly: true
|
readOnly: true
|
||||||
@@ -74,11 +86,16 @@ spec:
|
|||||||
- "--upstream=http://127.0.0.1:8080/"
|
- "--upstream=http://127.0.0.1:8080/"
|
||||||
- "--logtostderr=true"
|
- "--logtostderr=true"
|
||||||
- "--v=10"
|
- "--v=10"
|
||||||
image: gcr.io/kubebuilder/kube-rbac-proxy:v0.4.1
|
image: "{{ .Values.kube_rbac_proxy.image.repository }}:{{ .Values.kube_rbac_proxy.image.tag }}"
|
||||||
name: kube-rbac-proxy
|
name: kube-rbac-proxy
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8443
|
- containerPort: 8443
|
||||||
name: https
|
name: https
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
terminationGracePeriodSeconds: 10
|
terminationGracePeriodSeconds: 10
|
||||||
volumes:
|
volumes:
|
||||||
- name: controller-manager
|
- name: controller-manager
|
||||||
@@ -88,6 +105,8 @@ spec:
|
|||||||
secret:
|
secret:
|
||||||
defaultMode: 420
|
defaultMode: 420
|
||||||
secretName: webhook-server-cert
|
secretName: webhook-server-cert
|
||||||
|
- name: tmp
|
||||||
|
emptyDir: {}
|
||||||
{{- with .Values.nodeSelector }}
|
{{- with .Values.nodeSelector }}
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{{- if or .Values.authSecret.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: controller-manager
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "actions-runner-controller.labels" . | nindent 4 }}
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
{{- range $k, $v := .Values.authSecret }}
|
||||||
|
{{ $k }}: {{ $v | toString | b64enc }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -2,15 +2,34 @@
|
|||||||
# This is a YAML-formatted file.
|
# This is a YAML-formatted file.
|
||||||
# Declare variables to be passed into your templates.
|
# Declare variables to be passed into your templates.
|
||||||
|
|
||||||
|
labels: {}
|
||||||
|
|
||||||
replicaCount: 1
|
replicaCount: 1
|
||||||
|
|
||||||
syncPeriod: 10m
|
syncPeriod: 10m
|
||||||
|
|
||||||
|
# Only 1 authentication method can be deployed at a time
|
||||||
|
# Uncomment the configuration you are applying and fill in the details
|
||||||
|
authSecret:
|
||||||
|
enabled: false
|
||||||
|
### GitHub Apps Configuration
|
||||||
|
#github_app_id: ""
|
||||||
|
#github_app_installation_id: ""
|
||||||
|
#github_app_private_key: |
|
||||||
|
### GitHub PAT Configuration
|
||||||
|
#github_token: ""
|
||||||
|
|
||||||
image:
|
image:
|
||||||
repository: summerwind/actions-runner-controller
|
repository: summerwind/actions-runner-controller
|
||||||
|
# Overrides the manager image tag whose default is the chart appVersion if the tag key is commented out
|
||||||
|
tag: "latest"
|
||||||
|
dindSidecarRepositoryAndTag: "docker:dind"
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
# Overrides the image tag whose default is the chart appVersion.
|
|
||||||
tag: ""
|
kube_rbac_proxy:
|
||||||
|
image:
|
||||||
|
repository: gcr.io/kubebuilder/kube-rbac-proxy
|
||||||
|
tag: v0.4.1
|
||||||
|
|
||||||
imagePullSecrets: []
|
imagePullSecrets: []
|
||||||
nameOverride: ""
|
nameOverride: ""
|
||||||
@@ -79,3 +98,13 @@ nodeSelector: {}
|
|||||||
tolerations: []
|
tolerations: []
|
||||||
|
|
||||||
affinity: {}
|
affinity: {}
|
||||||
|
|
||||||
|
# Leverage a PriorityClass to ensure your pods survive resource shortages
|
||||||
|
# ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/
|
||||||
|
# PriorityClass: system-cluster-critical
|
||||||
|
priorityClassName: ""
|
||||||
|
|
||||||
|
env: {}
|
||||||
|
# http_proxy: "proxy.com:8080"
|
||||||
|
# https_proxy: "proxy.com:8080"
|
||||||
|
# no_proxy: ""
|
||||||
@@ -64,6 +64,24 @@ spec:
|
|||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
scaleDownFactor:
|
||||||
|
description: ScaleDownFactor is the multiplicative factor applied
|
||||||
|
to the current number of runners used to determine how many
|
||||||
|
pods should be removed.
|
||||||
|
type: string
|
||||||
|
scaleDownThreshold:
|
||||||
|
description: ScaleDownThreshold is the percentage of busy runners
|
||||||
|
less than which will trigger the hpa to scale the runners down.
|
||||||
|
type: string
|
||||||
|
scaleUpFactor:
|
||||||
|
description: ScaleUpFactor is the multiplicative factor applied
|
||||||
|
to the current number of runners used to determine how many
|
||||||
|
pods should be added.
|
||||||
|
type: string
|
||||||
|
scaleUpThreshold:
|
||||||
|
description: ScaleUpThreshold is the percentage of busy runners
|
||||||
|
greater than which will trigger the hpa to scale runners up.
|
||||||
|
type: string
|
||||||
type:
|
type:
|
||||||
description: Type is the type of metric to be used for autoscaling.
|
description: Type is the type of metric to be used for autoscaling.
|
||||||
The only supported Type is TotalNumberOfQueuedAndInProgressWorkflowRuns
|
The only supported Type is TotalNumberOfQueuedAndInProgressWorkflowRuns
|
||||||
|
|||||||
@@ -400,6 +400,8 @@ spec:
|
|||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
dockerEnabled:
|
||||||
|
type: boolean
|
||||||
dockerdContainerResources:
|
dockerdContainerResources:
|
||||||
description: ResourceRequirements describes the compute resource requirements.
|
description: ResourceRequirements describes the compute resource requirements.
|
||||||
properties:
|
properties:
|
||||||
@@ -1531,6 +1533,8 @@ spec:
|
|||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
workDir:
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
|
|||||||
@@ -400,6 +400,8 @@ spec:
|
|||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
dockerEnabled:
|
||||||
|
type: boolean
|
||||||
dockerdContainerResources:
|
dockerdContainerResources:
|
||||||
description: ResourceRequirements describes the compute resource requirements.
|
description: ResourceRequirements describes the compute resource requirements.
|
||||||
properties:
|
properties:
|
||||||
@@ -1531,6 +1533,8 @@ spec:
|
|||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
workDir:
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
|
|||||||
@@ -393,6 +393,8 @@ spec:
|
|||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
dockerEnabled:
|
||||||
|
type: boolean
|
||||||
dockerdContainerResources:
|
dockerdContainerResources:
|
||||||
description: ResourceRequirements describes the compute resource requirements.
|
description: ResourceRequirements describes the compute resource requirements.
|
||||||
properties:
|
properties:
|
||||||
@@ -1524,6 +1526,8 @@ spec:
|
|||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
workDir:
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
status:
|
status:
|
||||||
description: RunnerStatus defines the observed state of Runner
|
description: RunnerStatus defines the observed state of Runner
|
||||||
|
|||||||
@@ -4,9 +4,19 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/summerwind/actions-runner-controller/api/v1alpha1"
|
"github.com/summerwind/actions-runner-controller/api/v1alpha1"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultScaleUpThreshold = 0.8
|
||||||
|
defaultScaleDownThreshold = 0.3
|
||||||
|
defaultScaleUpFactor = 1.3
|
||||||
|
defaultScaleDownFactor = 0.7
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *HorizontalRunnerAutoscalerReconciler) determineDesiredReplicas(rd v1alpha1.RunnerDeployment, hra v1alpha1.HorizontalRunnerAutoscaler) (*int, error) {
|
func (r *HorizontalRunnerAutoscalerReconciler) determineDesiredReplicas(rd v1alpha1.RunnerDeployment, hra v1alpha1.HorizontalRunnerAutoscaler) (*int, error) {
|
||||||
@@ -16,8 +26,20 @@ func (r *HorizontalRunnerAutoscalerReconciler) determineDesiredReplicas(rd v1alp
|
|||||||
return nil, fmt.Errorf("horizontalrunnerautoscaler %s/%s is missing maxReplicas", hra.Namespace, hra.Name)
|
return nil, fmt.Errorf("horizontalrunnerautoscaler %s/%s is missing maxReplicas", hra.Namespace, hra.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
var repos [][]string
|
metrics := hra.Spec.Metrics
|
||||||
|
if len(metrics) == 0 || metrics[0].Type == v1alpha1.AutoscalingMetricTypeTotalNumberOfQueuedAndInProgressWorkflowRuns {
|
||||||
|
return r.calculateReplicasByQueuedAndInProgressWorkflowRuns(rd, hra)
|
||||||
|
} else if metrics[0].Type == v1alpha1.AutoscalingMetricTypePercentageRunnersBusy {
|
||||||
|
return r.calculateReplicasByPercentageRunnersBusy(rd, hra)
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("validting autoscaling metrics: unsupported metric type %q", metrics[0].Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HorizontalRunnerAutoscalerReconciler) calculateReplicasByQueuedAndInProgressWorkflowRuns(rd v1alpha1.RunnerDeployment, hra v1alpha1.HorizontalRunnerAutoscaler) (*int, error) {
|
||||||
|
|
||||||
|
var repos [][]string
|
||||||
|
metrics := hra.Spec.Metrics
|
||||||
repoID := rd.Spec.Template.Spec.Repository
|
repoID := rd.Spec.Template.Spec.Repository
|
||||||
if repoID == "" {
|
if repoID == "" {
|
||||||
orgName := rd.Spec.Template.Spec.Organization
|
orgName := rd.Spec.Template.Spec.Organization
|
||||||
@@ -25,13 +47,7 @@ func (r *HorizontalRunnerAutoscalerReconciler) determineDesiredReplicas(rd v1alp
|
|||||||
return nil, fmt.Errorf("asserting runner deployment spec to detect bug: spec.template.organization should not be empty on this code path")
|
return nil, fmt.Errorf("asserting runner deployment spec to detect bug: spec.template.organization should not be empty on this code path")
|
||||||
}
|
}
|
||||||
|
|
||||||
metrics := hra.Spec.Metrics
|
if len(metrics[0].RepositoryNames) == 0 {
|
||||||
|
|
||||||
if len(metrics) == 0 {
|
|
||||||
return nil, fmt.Errorf("validating autoscaling metrics: one or more metrics is required")
|
|
||||||
} else if tpe := metrics[0].Type; tpe != v1alpha1.AutoscalingMetricTypeTotalNumberOfQueuedAndInProgressWorkflowRuns {
|
|
||||||
return nil, fmt.Errorf("validting autoscaling metrics: unsupported metric type %q: only supported value is %s", tpe, v1alpha1.AutoscalingMetricTypeTotalNumberOfQueuedAndInProgressWorkflowRuns)
|
|
||||||
} else if len(metrics[0].RepositoryNames) == 0 {
|
|
||||||
return nil, errors.New("validating autoscaling metrics: spec.autoscaling.metrics[].repositoryNames is required and must have one more more entries for organizational runner deployment")
|
return nil, errors.New("validating autoscaling metrics: spec.autoscaling.metrics[].repositoryNames is required and must have one more more entries for organizational runner deployment")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,3 +151,99 @@ func (r *HorizontalRunnerAutoscalerReconciler) determineDesiredReplicas(rd v1alp
|
|||||||
|
|
||||||
return &replicas, nil
|
return &replicas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *HorizontalRunnerAutoscalerReconciler) calculateReplicasByPercentageRunnersBusy(rd v1alpha1.RunnerDeployment, hra v1alpha1.HorizontalRunnerAutoscaler) (*int, error) {
|
||||||
|
ctx := context.Background()
|
||||||
|
orgName := rd.Spec.Template.Spec.Organization
|
||||||
|
minReplicas := *hra.Spec.MinReplicas
|
||||||
|
maxReplicas := *hra.Spec.MaxReplicas
|
||||||
|
metrics := hra.Spec.Metrics[0]
|
||||||
|
scaleUpThreshold := defaultScaleUpThreshold
|
||||||
|
scaleDownThreshold := defaultScaleDownThreshold
|
||||||
|
scaleUpFactor := defaultScaleUpFactor
|
||||||
|
scaleDownFactor := defaultScaleDownFactor
|
||||||
|
|
||||||
|
if metrics.ScaleUpThreshold != "" {
|
||||||
|
sut, err := strconv.ParseFloat(metrics.ScaleUpThreshold, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("validating autoscaling metrics: spec.autoscaling.metrics[].scaleUpThreshold cannot be parsed into a float64")
|
||||||
|
}
|
||||||
|
scaleUpThreshold = sut
|
||||||
|
}
|
||||||
|
if metrics.ScaleDownThreshold != "" {
|
||||||
|
sdt, err := strconv.ParseFloat(metrics.ScaleDownThreshold, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("validating autoscaling metrics: spec.autoscaling.metrics[].scaleDownThreshold cannot be parsed into a float64")
|
||||||
|
}
|
||||||
|
|
||||||
|
scaleDownThreshold = sdt
|
||||||
|
}
|
||||||
|
if metrics.ScaleUpFactor != "" {
|
||||||
|
suf, err := strconv.ParseFloat(metrics.ScaleUpFactor, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("validating autoscaling metrics: spec.autoscaling.metrics[].scaleUpFactor cannot be parsed into a float64")
|
||||||
|
}
|
||||||
|
scaleUpFactor = suf
|
||||||
|
}
|
||||||
|
if metrics.ScaleDownFactor != "" {
|
||||||
|
sdf, err := strconv.ParseFloat(metrics.ScaleDownFactor, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("validating autoscaling metrics: spec.autoscaling.metrics[].scaleDownFactor cannot be parsed into a float64")
|
||||||
|
}
|
||||||
|
scaleDownFactor = sdf
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the list of runners in namespace. Horizontal Runner Autoscaler should only be responsible for scaling resources in its own ns.
|
||||||
|
var runnerList v1alpha1.RunnerList
|
||||||
|
if err := r.List(ctx, &runnerList, client.InNamespace(rd.Namespace)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
runnerMap := make(map[string]struct{})
|
||||||
|
for _, items := range runnerList.Items {
|
||||||
|
runnerMap[items.Name] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListRunners will return all runners managed by GitHub - not restricted to ns
|
||||||
|
runners, err := r.GitHubClient.ListRunners(ctx, orgName, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
numRunners := len(runnerList.Items)
|
||||||
|
numRunnersBusy := 0
|
||||||
|
for _, runner := range runners {
|
||||||
|
if _, ok := runnerMap[*runner.Name]; ok && runner.GetBusy() {
|
||||||
|
numRunnersBusy++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var desiredReplicas int
|
||||||
|
fractionBusy := float64(numRunnersBusy) / float64(numRunners)
|
||||||
|
if fractionBusy >= scaleUpThreshold {
|
||||||
|
desiredReplicas = int(math.Ceil(float64(numRunners) * scaleUpFactor))
|
||||||
|
} else if fractionBusy < scaleDownThreshold {
|
||||||
|
desiredReplicas = int(float64(numRunners) * scaleDownFactor)
|
||||||
|
} else {
|
||||||
|
desiredReplicas = *rd.Spec.Replicas
|
||||||
|
}
|
||||||
|
|
||||||
|
if desiredReplicas < minReplicas {
|
||||||
|
desiredReplicas = minReplicas
|
||||||
|
} else if desiredReplicas > maxReplicas {
|
||||||
|
desiredReplicas = maxReplicas
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Log.V(1).Info(
|
||||||
|
"Calculated desired replicas",
|
||||||
|
"computed_replicas_desired", desiredReplicas,
|
||||||
|
"spec_replicas_min", minReplicas,
|
||||||
|
"spec_replicas_max", maxReplicas,
|
||||||
|
"current_replicas", rd.Spec.Replicas,
|
||||||
|
"num_runners", numRunners,
|
||||||
|
"num_runners_busy", numRunnersBusy,
|
||||||
|
)
|
||||||
|
|
||||||
|
rd.Status.Replicas = &desiredReplicas
|
||||||
|
replicas := desiredReplicas
|
||||||
|
|
||||||
|
return &replicas, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"github.com/summerwind/actions-runner-controller/hash"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
@@ -39,6 +39,8 @@ import (
|
|||||||
const (
|
const (
|
||||||
containerName = "runner"
|
containerName = "runner"
|
||||||
finalizerName = "runner.actions.summerwind.dev"
|
finalizerName = "runner.actions.summerwind.dev"
|
||||||
|
|
||||||
|
LabelKeyPodTemplateHash = "pod-template-hash"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RunnerReconciler reconciles a Runner object
|
// RunnerReconciler reconciles a Runner object
|
||||||
@@ -198,14 +200,21 @@ func (r *RunnerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
|||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !runnerBusy && (!reflect.DeepEqual(pod.Spec.Containers[0].Env, newPod.Spec.Containers[0].Env) || pod.Spec.Containers[0].Image != newPod.Spec.Containers[0].Image) {
|
// See the `newPod` function called above for more information
|
||||||
|
// about when this hash changes.
|
||||||
|
curHash := pod.Labels[LabelKeyPodTemplateHash]
|
||||||
|
newHash := newPod.Labels[LabelKeyPodTemplateHash]
|
||||||
|
|
||||||
|
if !runnerBusy && curHash != newHash {
|
||||||
restart = true
|
restart = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't do anything if there's no need to restart the runner
|
||||||
if !restart {
|
if !restart {
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete current pod if recreation is needed
|
||||||
if err := r.Delete(ctx, &pod); err != nil {
|
if err := r.Delete(ctx, &pod); err != nil {
|
||||||
log.Error(err, "Failed to delete pod resource")
|
log.Error(err, "Failed to delete pod resource")
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
@@ -299,6 +308,7 @@ func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) {
|
|||||||
var (
|
var (
|
||||||
privileged bool = true
|
privileged bool = true
|
||||||
dockerdInRunner bool = runner.Spec.DockerdWithinRunnerContainer != nil && *runner.Spec.DockerdWithinRunnerContainer
|
dockerdInRunner bool = runner.Spec.DockerdWithinRunnerContainer != nil && *runner.Spec.DockerdWithinRunnerContainer
|
||||||
|
dockerEnabled bool = runner.Spec.DockerEnabled == nil || *runner.Spec.DockerEnabled
|
||||||
)
|
)
|
||||||
|
|
||||||
runnerImage := runner.Spec.Image
|
runnerImage := runner.Spec.Image
|
||||||
@@ -306,6 +316,11 @@ func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) {
|
|||||||
runnerImage = r.RunnerImage
|
runnerImage = r.RunnerImage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
workDir := runner.Spec.WorkDir
|
||||||
|
if workDir == "" {
|
||||||
|
workDir = "/runner/_work"
|
||||||
|
}
|
||||||
|
|
||||||
runnerImagePullPolicy := runner.Spec.ImagePullPolicy
|
runnerImagePullPolicy := runner.Spec.ImagePullPolicy
|
||||||
if runnerImagePullPolicy == "" {
|
if runnerImagePullPolicy == "" {
|
||||||
runnerImagePullPolicy = corev1.PullAlways
|
runnerImagePullPolicy = corev1.PullAlways
|
||||||
@@ -344,14 +359,51 @@ func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) {
|
|||||||
Name: "GITHUB_URL",
|
Name: "GITHUB_URL",
|
||||||
Value: r.GitHubClient.GithubBaseURL,
|
Value: r.GitHubClient.GithubBaseURL,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "RUNNER_WORKDIR",
|
||||||
|
Value: workDir,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
env = append(env, runner.Spec.Env...)
|
env = append(env, runner.Spec.Env...)
|
||||||
|
|
||||||
|
labels := map[string]string{}
|
||||||
|
|
||||||
|
for k, v := range runner.Labels {
|
||||||
|
labels[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// This implies that...
|
||||||
|
//
|
||||||
|
// (1) We recreate the runner pod whenever the runner has changes in:
|
||||||
|
// - metadata.labels (excluding "runner-template-hash" added by the parent RunnerReplicaSet
|
||||||
|
// - metadata.annotations
|
||||||
|
// - metadata.spec (including image, env, organization, repository, group, and so on)
|
||||||
|
// - GithubBaseURL setting of the controller (can be configured via GITHUB_ENTERPRISE_URL)
|
||||||
|
//
|
||||||
|
// (2) We don't recreate the runner pod when there are changes in:
|
||||||
|
// - runner.status.registration.token
|
||||||
|
// - This token expires and changes hourly, but you don't need to recreate the pod due to that.
|
||||||
|
// It's the opposite.
|
||||||
|
// An unexpired token is required only when the runner agent is registering itself on launch.
|
||||||
|
//
|
||||||
|
// In other words, the registered runner doesn't get invalidated on registration token expiration.
|
||||||
|
// A registered runner's session and the a registration token seem to have two different and independent
|
||||||
|
// lifecycles.
|
||||||
|
//
|
||||||
|
// See https://github.com/summerwind/actions-runner-controller/issues/143 for more context.
|
||||||
|
labels[LabelKeyPodTemplateHash] = hash.FNVHashStringObjects(
|
||||||
|
filterLabels(runner.Labels, LabelKeyRunnerTemplateHash),
|
||||||
|
runner.Annotations,
|
||||||
|
runner.Spec,
|
||||||
|
r.GitHubClient.GithubBaseURL,
|
||||||
|
)
|
||||||
|
|
||||||
pod := corev1.Pod{
|
pod := corev1.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: runner.Name,
|
Name: runner.Name,
|
||||||
Namespace: runner.Namespace,
|
Namespace: runner.Namespace,
|
||||||
Labels: runner.Labels,
|
Labels: labels,
|
||||||
Annotations: runner.Annotations,
|
Annotations: runner.Annotations,
|
||||||
},
|
},
|
||||||
Spec: corev1.PodSpec{
|
Spec: corev1.PodSpec{
|
||||||
@@ -373,7 +425,10 @@ func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if !dockerdInRunner {
|
if !dockerdInRunner && dockerEnabled {
|
||||||
|
runnerVolumeName := "runner"
|
||||||
|
runnerVolumeMountPath := "/runner"
|
||||||
|
|
||||||
pod.Spec.Volumes = []corev1.Volume{
|
pod.Spec.Volumes = []corev1.Volume{
|
||||||
{
|
{
|
||||||
Name: "work",
|
Name: "work",
|
||||||
@@ -382,7 +437,13 @@ func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "docker",
|
Name: runnerVolumeName,
|
||||||
|
VolumeSource: corev1.VolumeSource{
|
||||||
|
EmptyDir: &corev1.EmptyDirVolumeSource{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "certs-client",
|
||||||
VolumeSource: corev1.VolumeSource{
|
VolumeSource: corev1.VolumeSource{
|
||||||
EmptyDir: &corev1.EmptyDirVolumeSource{},
|
EmptyDir: &corev1.EmptyDirVolumeSource{},
|
||||||
},
|
},
|
||||||
@@ -391,29 +452,59 @@ func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) {
|
|||||||
pod.Spec.Containers[0].VolumeMounts = []corev1.VolumeMount{
|
pod.Spec.Containers[0].VolumeMounts = []corev1.VolumeMount{
|
||||||
{
|
{
|
||||||
Name: "work",
|
Name: "work",
|
||||||
MountPath: "/runner/_work",
|
MountPath: workDir,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "docker",
|
Name: runnerVolumeName,
|
||||||
MountPath: "/var/run",
|
MountPath: runnerVolumeMountPath,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "certs-client",
|
||||||
|
MountPath: "/certs/client",
|
||||||
|
ReadOnly: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
pod.Spec.Containers[0].Env = append(pod.Spec.Containers[0].Env, []corev1.EnvVar{
|
||||||
|
{
|
||||||
|
Name: "DOCKER_HOST",
|
||||||
|
Value: "tcp://localhost:2376",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "DOCKER_TLS_VERIFY",
|
||||||
|
Value: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "DOCKER_CERT_PATH",
|
||||||
|
Value: "/certs/client",
|
||||||
|
},
|
||||||
|
}...)
|
||||||
pod.Spec.Containers = append(pod.Spec.Containers, corev1.Container{
|
pod.Spec.Containers = append(pod.Spec.Containers, corev1.Container{
|
||||||
Name: "docker",
|
Name: "docker",
|
||||||
Image: r.DockerImage,
|
Image: r.DockerImage,
|
||||||
VolumeMounts: []corev1.VolumeMount{
|
VolumeMounts: []corev1.VolumeMount{
|
||||||
{
|
{
|
||||||
Name: "work",
|
Name: "work",
|
||||||
MountPath: "/runner/_work",
|
MountPath: workDir,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "docker",
|
Name: runnerVolumeName,
|
||||||
MountPath: "/var/run",
|
MountPath: runnerVolumeMountPath,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "certs-client",
|
||||||
|
MountPath: "/certs/client",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Env: []corev1.EnvVar{
|
||||||
|
{
|
||||||
|
Name: "DOCKER_TLS_CERTDIR",
|
||||||
|
Value: "/certs",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
SecurityContext: &corev1.SecurityContext{
|
SecurityContext: &corev1.SecurityContext{
|
||||||
Privileged: &privileged,
|
Privileged: &privileged,
|
||||||
},
|
},
|
||||||
|
Resources: runner.Spec.DockerdContainerResources,
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ type RunnerReplicaSetReconciler struct {
|
|||||||
|
|
||||||
func (r *RunnerReplicaSetReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
func (r *RunnerReplicaSetReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
log := r.Log.WithValues("runner", req.NamespacedName)
|
log := r.Log.WithValues("runnerreplicaset", req.NamespacedName)
|
||||||
|
|
||||||
var rs v1alpha1.RunnerReplicaSet
|
var rs v1alpha1.RunnerReplicaSet
|
||||||
if err := r.Get(ctx, req.NamespacedName, &rs); err != nil {
|
if err := r.Get(ctx, req.NamespacedName, &rs); err != nil {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/go-github/v32/github"
|
"github.com/google/go-github/v33/github"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/client-go/kubernetes/scheme"
|
"k8s.io/client-go/kubernetes/scheme"
|
||||||
|
|||||||
13
controllers/utils.go
Normal file
13
controllers/utils.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
func filterLabels(labels map[string]string, filter string) map[string]string {
|
||||||
|
filtered := map[string]string{}
|
||||||
|
|
||||||
|
for k, v := range labels {
|
||||||
|
if k != filter {
|
||||||
|
filtered[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered
|
||||||
|
}
|
||||||
34
controllers/utils_test.go
Normal file
34
controllers/utils_test.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_filterLabels(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
labels map[string]string
|
||||||
|
filter string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want map[string]string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "ok",
|
||||||
|
args: args{
|
||||||
|
labels: map[string]string{LabelKeyRunnerTemplateHash: "abc", LabelKeyPodTemplateHash: "def"},
|
||||||
|
filter: LabelKeyRunnerTemplateHash,
|
||||||
|
},
|
||||||
|
want: map[string]string{LabelKeyPodTemplateHash: "def"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := filterLabels(tt.args.labels, tt.args.filter); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("filterLabels() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/google/go-github/v32/github"
|
"github.com/google/go-github/v33/github"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bradleyfalzon/ghinstallation"
|
"github.com/bradleyfalzon/ghinstallation"
|
||||||
"github.com/google/go-github/v32/github"
|
"github.com/google/go-github/v33/github"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -32,6 +32,7 @@ type Client struct {
|
|||||||
GithubBaseURL string
|
GithubBaseURL string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewClient creates a Github Client
|
||||||
func (c *Config) NewClient() (*Client, error) {
|
func (c *Config) NewClient() (*Client, error) {
|
||||||
var (
|
var (
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
@@ -84,7 +85,7 @@ func (c *Client) GetRegistrationToken(ctx context.Context, org, repo, name strin
|
|||||||
key := getRegistrationKey(org, repo)
|
key := getRegistrationKey(org, repo)
|
||||||
rt, ok := c.regTokens[key]
|
rt, ok := c.regTokens[key]
|
||||||
|
|
||||||
if ok && rt.GetExpiresAt().After(time.Now().Add(-10*time.Minute)) {
|
if ok && rt.GetExpiresAt().After(time.Now()) {
|
||||||
return rt, nil
|
return rt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,25 +180,25 @@ func (c *Client) cleanup() {
|
|||||||
func (c *Client) createRegistrationToken(ctx context.Context, owner, repo string) (*github.RegistrationToken, *github.Response, error) {
|
func (c *Client) createRegistrationToken(ctx context.Context, owner, repo string) (*github.RegistrationToken, *github.Response, error) {
|
||||||
if len(repo) > 0 {
|
if len(repo) > 0 {
|
||||||
return c.Client.Actions.CreateRegistrationToken(ctx, owner, repo)
|
return c.Client.Actions.CreateRegistrationToken(ctx, owner, repo)
|
||||||
} else {
|
|
||||||
return CreateOrganizationRegistrationToken(ctx, c, owner)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return c.Client.Actions.CreateOrganizationRegistrationToken(ctx, owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) removeRunner(ctx context.Context, owner, repo string, runnerID int64) (*github.Response, error) {
|
func (c *Client) removeRunner(ctx context.Context, owner, repo string, runnerID int64) (*github.Response, error) {
|
||||||
if len(repo) > 0 {
|
if len(repo) > 0 {
|
||||||
return c.Client.Actions.RemoveRunner(ctx, owner, repo, runnerID)
|
return c.Client.Actions.RemoveRunner(ctx, owner, repo, runnerID)
|
||||||
} else {
|
|
||||||
return RemoveOrganizationRunner(ctx, c, owner, runnerID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return c.Client.Actions.RemoveOrganizationRunner(ctx, owner, runnerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) listRunners(ctx context.Context, owner, repo string, opts *github.ListOptions) (*github.Runners, *github.Response, error) {
|
func (c *Client) listRunners(ctx context.Context, owner, repo string, opts *github.ListOptions) (*github.Runners, *github.Response, error) {
|
||||||
if len(repo) > 0 {
|
if len(repo) > 0 {
|
||||||
return c.Client.Actions.ListRunners(ctx, owner, repo, opts)
|
return c.Client.Actions.ListRunners(ctx, owner, repo, opts)
|
||||||
} else {
|
|
||||||
return ListOrganizationRunners(ctx, c, owner, opts)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return c.Client.Actions.ListOrganizationRunners(ctx, owner, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validates owner and repo arguments. Both are optional, but at least one should be specified
|
// Validates owner and repo arguments. Both are optional, but at least one should be specified
|
||||||
@@ -214,9 +215,8 @@ func getOwnerAndRepo(org, repo string) (string, string, error) {
|
|||||||
func getRegistrationKey(org, repo string) string {
|
func getRegistrationKey(org, repo string) string {
|
||||||
if len(org) > 0 {
|
if len(org) > 0 {
|
||||||
return org
|
return org
|
||||||
} else {
|
|
||||||
return repo
|
|
||||||
}
|
}
|
||||||
|
return repo
|
||||||
}
|
}
|
||||||
|
|
||||||
func splitOwnerAndRepo(repo string) (string, string, error) {
|
func splitOwnerAndRepo(repo string) (string, string, error) {
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
package github
|
|
||||||
|
|
||||||
// this contains BETA API clients, that are currently not (yet) in go-github
|
|
||||||
// once these functions have been added there, they can be removed from here
|
|
||||||
// code was reused from https://github.com/google/go-github
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"github.com/google/go-github/v32/github"
|
|
||||||
"github.com/google/go-querystring/query"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CreateOrganizationRegistrationToken creates a token that can be used to add a self-hosted runner on an organization.
|
|
||||||
//
|
|
||||||
// GitHub API docs: https://developer.github.com/v3/actions/self-hosted-runners/#create-a-registration-token-for-an-organization
|
|
||||||
func CreateOrganizationRegistrationToken(ctx context.Context, client *Client, owner string) (*github.RegistrationToken, *github.Response, error) {
|
|
||||||
u := fmt.Sprintf("orgs/%v/actions/runners/registration-token", owner)
|
|
||||||
|
|
||||||
req, err := client.NewRequest("POST", u, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
registrationToken := new(github.RegistrationToken)
|
|
||||||
resp, err := client.Do(ctx, req, registrationToken)
|
|
||||||
if err != nil {
|
|
||||||
return nil, resp, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return registrationToken, resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListOrganizationRunners lists all the self-hosted runners for an organization.
|
|
||||||
//
|
|
||||||
// GitHub API docs: https://developer.github.com/v3/actions/self-hosted-runners/#list-self-hosted-runners-for-an-organization
|
|
||||||
func ListOrganizationRunners(ctx context.Context, client *Client, owner string, opts *github.ListOptions) (*github.Runners, *github.Response, error) {
|
|
||||||
u := fmt.Sprintf("orgs/%v/actions/runners", owner)
|
|
||||||
u, err := addOptions(u, opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := client.NewRequest("GET", u, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
runners := &github.Runners{}
|
|
||||||
resp, err := client.Do(ctx, req, &runners)
|
|
||||||
if err != nil {
|
|
||||||
return nil, resp, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return runners, resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveOrganizationRunner forces the removal of a self-hosted runner in a repository using the runner id.
|
|
||||||
//
|
|
||||||
// GitHub API docs: https://developer.github.com/v3/actions/self_hosted_runners/#remove-a-self-hosted-runner
|
|
||||||
func RemoveOrganizationRunner(ctx context.Context, client *Client, owner string, runnerID int64) (*github.Response, error) {
|
|
||||||
u := fmt.Sprintf("orgs/%v/actions/runners/%v", owner, runnerID)
|
|
||||||
|
|
||||||
req, err := client.NewRequest("DELETE", u, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return client.Do(ctx, req, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// addOptions adds the parameters in opt as URL query parameters to s. opt
|
|
||||||
// must be a struct whose fields may contain "url" tags.
|
|
||||||
func addOptions(s string, opts interface{}) (string, error) {
|
|
||||||
v := reflect.ValueOf(opts)
|
|
||||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
u, err := url.Parse(s)
|
|
||||||
if err != nil {
|
|
||||||
return s, err
|
|
||||||
}
|
|
||||||
|
|
||||||
qs, err := query.Values(opts)
|
|
||||||
if err != nil {
|
|
||||||
return s, err
|
|
||||||
}
|
|
||||||
|
|
||||||
u.RawQuery = qs.Encode()
|
|
||||||
return u.String(), nil
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/go-github/v32/github"
|
"github.com/google/go-github/v33/github"
|
||||||
"github.com/summerwind/actions-runner-controller/github/fake"
|
"github.com/summerwind/actions-runner-controller/github/fake"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -6,7 +6,9 @@ require (
|
|||||||
github.com/bradleyfalzon/ghinstallation v1.1.1
|
github.com/bradleyfalzon/ghinstallation v1.1.1
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/go-logr/logr v0.1.0
|
github.com/go-logr/logr v0.1.0
|
||||||
|
github.com/google/go-github v17.0.0+incompatible // indirect
|
||||||
github.com/google/go-github/v32 v32.1.1-0.20200822031813-d57a3a84ba04
|
github.com/google/go-github/v32 v32.1.1-0.20200822031813-d57a3a84ba04
|
||||||
|
github.com/google/go-github/v33 v33.0.0
|
||||||
github.com/google/go-querystring v1.0.0
|
github.com/google/go-querystring v1.0.0
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/kelseyhightower/envconfig v1.4.0
|
github.com/kelseyhightower/envconfig v1.4.0
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -116,10 +116,14 @@ github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
|||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
||||||
|
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||||
github.com/google/go-github/v29 v29.0.2 h1:opYN6Wc7DOz7Ku3Oh4l7prmkOMwEcQxpFtxdU8N8Pts=
|
github.com/google/go-github/v29 v29.0.2 h1:opYN6Wc7DOz7Ku3Oh4l7prmkOMwEcQxpFtxdU8N8Pts=
|
||||||
github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E=
|
github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E=
|
||||||
github.com/google/go-github/v32 v32.1.1-0.20200822031813-d57a3a84ba04 h1:wEYk2h/GwOhImcVjiTIceP88WxVbXw2F+ARYUQMEsfg=
|
github.com/google/go-github/v32 v32.1.1-0.20200822031813-d57a3a84ba04 h1:wEYk2h/GwOhImcVjiTIceP88WxVbXw2F+ARYUQMEsfg=
|
||||||
github.com/google/go-github/v32 v32.1.1-0.20200822031813-d57a3a84ba04/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
|
github.com/google/go-github/v32 v32.1.1-0.20200822031813-d57a3a84ba04/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
|
||||||
|
github.com/google/go-github/v33 v33.0.0 h1:qAf9yP0qc54ufQxzwv+u9H0tiVOnPJxo0lI/JXqw3ZM=
|
||||||
|
github.com/google/go-github/v33 v33.0.0/go.mod h1:GMdDnVZY/2TsWgp/lkYnpSAh6TrzhANBBwm6k6TTEXg=
|
||||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||||
|
|||||||
19
hack/make-env.sh
Executable file
19
hack/make-env.sh
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
COMMIT=$(git rev-parse HEAD)
|
||||||
|
TAG=$(git describe --exact-match --abbrev=0 --tags "${COMMIT}" 2> /dev/null || true)
|
||||||
|
BRANCH=$(git branch | grep \* | cut -d ' ' -f2 | sed -e 's/[^a-zA-Z0-9+=._:/-]*//g' || true)
|
||||||
|
VERSION=""
|
||||||
|
|
||||||
|
if [ -z "$TAG" ]; then
|
||||||
|
[[ -n "$BRANCH" ]] && VERSION="${BRANCH}-"
|
||||||
|
VERSION="${VERSION}${COMMIT:0:8}"
|
||||||
|
else
|
||||||
|
VERSION=$TAG
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$(git diff --shortstat 2> /dev/null | tail -n1)" ]; then
|
||||||
|
VERSION="${VERSION}-dirty"
|
||||||
|
fi
|
||||||
|
|
||||||
|
export VERSION
|
||||||
17
hash/fnv.go
Normal file
17
hash/fnv.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package hash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"hash/fnv"
|
||||||
|
"k8s.io/apimachinery/pkg/util/rand"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FNVHashStringObjects(objs ...interface{}) string {
|
||||||
|
hash := fnv.New32a()
|
||||||
|
|
||||||
|
for _, obj := range objs {
|
||||||
|
DeepHashObject(hash, obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rand.SafeEncodeString(fmt.Sprint(hash.Sum32()))
|
||||||
|
}
|
||||||
25
hash/hash.go
Normal file
25
hash/hash.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2015 The Kubernetes Authors.
|
||||||
|
// hash.go is copied from kubernetes's pkg/util/hash.go
|
||||||
|
// See https://github.com/kubernetes/kubernetes/blob/e1c617a88ec286f5f6cb2589d6ac562d095e1068/pkg/util/hash/hash.go#L25-L37
|
||||||
|
|
||||||
|
package hash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"hash"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeepHashObject writes specified object to hash using the spew library
|
||||||
|
// which follows pointers and prints actual values of the nested objects
|
||||||
|
// ensuring the hash does not change when a pointer changes.
|
||||||
|
func DeepHashObject(hasher hash.Hash, objectToWrite interface{}) {
|
||||||
|
hasher.Reset()
|
||||||
|
printer := spew.ConfigState{
|
||||||
|
Indent: " ",
|
||||||
|
SortKeys: true,
|
||||||
|
DisableMethods: true,
|
||||||
|
SpewKeys: true,
|
||||||
|
}
|
||||||
|
printer.Fprintf(hasher, "%#v", objectToWrite)
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
FROM ubuntu:18.04
|
FROM ubuntu:18.04
|
||||||
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
||||||
ARG RUNNER_VERSION=2.274.1
|
ARG RUNNER_VERSION=2.274.2
|
||||||
ARG DOCKER_VERSION=19.03.12
|
ARG DOCKER_VERSION=19.03.12
|
||||||
|
|
||||||
|
RUN test -n "$TARGETPLATFORM" || (echo "TARGETPLATFORM must be set" && false)
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
RUN apt update -y \
|
RUN apt update -y \
|
||||||
&& apt install -y software-properties-common \
|
&& apt install -y software-properties-common \
|
||||||
@@ -42,7 +44,8 @@ RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
|
|||||||
&& chmod +x /usr/local/bin/dumb-init
|
&& chmod +x /usr/local/bin/dumb-init
|
||||||
|
|
||||||
# Docker download supports arm64 as aarch64 & amd64 as x86_64
|
# Docker download supports arm64 as aarch64 & amd64 as x86_64
|
||||||
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
|
RUN set -vx; \
|
||||||
|
export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
|
||||||
&& if [ "$ARCH" = "arm64" ]; then export ARCH=aarch64 ; fi \
|
&& if [ "$ARCH" = "arm64" ]; then export ARCH=aarch64 ; fi \
|
||||||
&& if [ "$ARCH" = "amd64" ]; then export ARCH=x86_64 ; fi \
|
&& if [ "$ARCH" = "amd64" ]; then export ARCH=x86_64 ; fi \
|
||||||
&& curl -L -o docker.tgz https://download.docker.com/linux/static/stable/${ARCH}/docker-${DOCKER_VERSION}.tgz \
|
&& curl -L -o docker.tgz https://download.docker.com/linux/static/stable/${ARCH}/docker-${DOCKER_VERSION}.tgz \
|
||||||
@@ -55,20 +58,33 @@ RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
|
|||||||
&& usermod -aG docker runner \
|
&& usermod -aG docker runner \
|
||||||
&& echo "%sudo ALL=(ALL:ALL) NOPASSWD:ALL" > /etc/sudoers
|
&& echo "%sudo ALL=(ALL:ALL) NOPASSWD:ALL" > /etc/sudoers
|
||||||
|
|
||||||
# Runner download supports amd64 as x64
|
ENV RUNNER_ASSETS_DIR=/runnertmp
|
||||||
|
|
||||||
|
# Runner download supports amd64 as x64. Externalstmp is needed for making mount points work inside DinD.
|
||||||
|
#
|
||||||
|
# libyaml-dev is required for ruby/setup-ruby action.
|
||||||
|
# It is installed after installdependencies.sh and before removing /var/lib/apt/lists
|
||||||
|
# to avoid rerunning apt-update on its own.
|
||||||
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
|
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
|
||||||
&& if [ "$ARCH" = "amd64" ]; then export ARCH=x64 ; fi \
|
&& if [ "$ARCH" = "amd64" ]; then export ARCH=x64 ; fi \
|
||||||
&& mkdir -p /runner \
|
&& mkdir -p "$RUNNER_ASSETS_DIR" \
|
||||||
&& cd /runner \
|
&& cd "$RUNNER_ASSETS_DIR" \
|
||||||
&& curl -L -o runner.tar.gz https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-${ARCH}-${RUNNER_VERSION}.tar.gz \
|
&& curl -L -o runner.tar.gz https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-${ARCH}-${RUNNER_VERSION}.tar.gz \
|
||||||
&& tar xzf ./runner.tar.gz \
|
&& tar xzf ./runner.tar.gz \
|
||||||
&& rm runner.tar.gz \
|
&& rm runner.tar.gz \
|
||||||
&& ./bin/installdependencies.sh \
|
&& ./bin/installdependencies.sh \
|
||||||
|
&& mv ./externals ./externalstmp \
|
||||||
|
&& apt-get install -y libyaml-dev \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
COPY entrypoint.sh /runner
|
RUN echo AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache > .env \
|
||||||
COPY patched /runner/patched
|
&& mkdir /opt/hostedtoolcache \
|
||||||
|
&& chgrp runner /opt/hostedtoolcache \
|
||||||
|
&& chmod g+rwx /opt/hostedtoolcache
|
||||||
|
|
||||||
|
COPY entrypoint.sh /
|
||||||
|
COPY patched $RUNNER_ASSETS_DIR/patched
|
||||||
|
|
||||||
USER runner
|
USER runner
|
||||||
ENTRYPOINT ["/usr/local/bin/dumb-init", "--"]
|
ENTRYPOINT ["/usr/local/bin/dumb-init", "--"]
|
||||||
CMD ["/runner/entrypoint.sh"]
|
CMD ["/entrypoint.sh"]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ NAME ?= summerwind/actions-runner
|
|||||||
DIND_RUNNER_NAME ?= ${NAME}-dind
|
DIND_RUNNER_NAME ?= ${NAME}-dind
|
||||||
TAG ?= latest
|
TAG ?= latest
|
||||||
|
|
||||||
RUNNER_VERSION ?= 2.273.5
|
RUNNER_VERSION ?= 2.274.2
|
||||||
DOCKER_VERSION ?= 19.03.12
|
DOCKER_VERSION ?= 19.03.12
|
||||||
|
|
||||||
# default list of platforms for which multiarch image is built
|
# default list of platforms for which multiarch image is built
|
||||||
@@ -23,15 +23,13 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
docker-build:
|
docker-build:
|
||||||
docker build --build-arg RUNNER_VERSION=${RUNNER_VERSION} --build-arg DOCKER_VERSION=${DOCKER_VERSION} -t ${NAME}:${TAG} -t ${NAME}:v${RUNNER_VERSION} .
|
docker build --build-arg TARGETPLATFORM=amd64 --build-arg RUNNER_VERSION=${RUNNER_VERSION} --build-arg DOCKER_VERSION=${DOCKER_VERSION} -t ${NAME}:${TAG} .
|
||||||
docker build --build-arg RUNNER_VERSION=${RUNNER_VERSION} --build-arg DOCKER_VERSION=${DOCKER_VERSION} -t ${DIND_RUNNER_NAME}:${TAG} -t ${DIND_RUNNER_NAME}:v${RUNNER_VERSION} -f dindrunner.Dockerfile .
|
docker build --build-arg TARGETPLATFORM=amd64 --build-arg RUNNER_VERSION=${RUNNER_VERSION} --build-arg DOCKER_VERSION=${DOCKER_VERSION} -t ${DIND_RUNNER_NAME}:${TAG} -f dindrunner.Dockerfile .
|
||||||
|
|
||||||
|
|
||||||
docker-push:
|
docker-push:
|
||||||
docker push ${NAME}:${TAG}
|
docker push ${NAME}:${TAG}
|
||||||
docker push ${NAME}:v${RUNNER_VERSION}
|
|
||||||
docker push ${DIND_RUNNER_NAME}:${TAG}
|
docker push ${DIND_RUNNER_NAME}:${TAG}
|
||||||
docker push ${DIND_RUNNER_NAME}:v${RUNNER_VERSION}
|
|
||||||
|
|
||||||
docker-buildx:
|
docker-buildx:
|
||||||
export DOCKER_CLI_EXPERIMENTAL=enabled
|
export DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ ARG DOCKER_CHANNEL=stable
|
|||||||
ARG DOCKER_VERSION=19.03.13
|
ARG DOCKER_VERSION=19.03.13
|
||||||
ARG DEBUG=false
|
ARG DEBUG=false
|
||||||
|
|
||||||
|
RUN test -n "$TARGETPLATFORM" || (echo "TARGETPLATFORM must be set" && false)
|
||||||
|
|
||||||
# Docker installation
|
# Docker installation
|
||||||
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
|
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
|
||||||
&& if [ "$ARCH" = "arm64" ]; then export ARCH=aarch64 ; fi \
|
&& if [ "$ARCH" = "arm64" ]; then export ARCH=aarch64 ; fi \
|
||||||
@@ -66,17 +68,28 @@ RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
|
|||||||
dockerd --version; \
|
dockerd --version; \
|
||||||
docker --version
|
docker --version
|
||||||
|
|
||||||
|
ENV RUNNER_ASSETS_DIR=/runnertmp
|
||||||
|
|
||||||
# Runner download supports amd64 as x64
|
# Runner download supports amd64 as x64
|
||||||
|
#
|
||||||
|
# libyaml-dev is required for ruby/setup-ruby action.
|
||||||
|
# It is installed after installdependencies.sh and before removing /var/lib/apt/lists
|
||||||
|
# to avoid rerunning apt-update on its own.
|
||||||
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
|
RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
|
||||||
&& if [ "$ARCH" = "amd64" ]; then export ARCH=x64 ; fi \
|
&& if [ "$ARCH" = "amd64" ]; then export ARCH=x64 ; fi \
|
||||||
&& mkdir -p /runner \
|
&& mkdir -p "$RUNNER_ASSETS_DIR" \
|
||||||
&& cd /runner \
|
&& cd "$RUNNER_ASSETS_DIR" \
|
||||||
&& curl -L -o runner.tar.gz https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-${ARCH}-${RUNNER_VERSION}.tar.gz \
|
&& curl -L -o runner.tar.gz https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-${ARCH}-${RUNNER_VERSION}.tar.gz \
|
||||||
&& tar xzf ./runner.tar.gz \
|
&& tar xzf ./runner.tar.gz \
|
||||||
&& rm runner.tar.gz \
|
&& rm runner.tar.gz \
|
||||||
&& ./bin/installdependencies.sh \
|
&& ./bin/installdependencies.sh \
|
||||||
|
&& apt-get install -y libyaml-dev \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN echo AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache > /runner.env \
|
||||||
|
&& mkdir /opt/hostedtoolcache \
|
||||||
|
&& chgrp runner /opt/hostedtoolcache \
|
||||||
|
&& chmod g+rwx /opt/hostedtoolcache
|
||||||
|
|
||||||
COPY modprobe startup.sh /usr/local/bin/
|
COPY modprobe startup.sh /usr/local/bin/
|
||||||
COPY supervisor/ /etc/supervisor/conf.d/
|
COPY supervisor/ /etc/supervisor/conf.d/
|
||||||
@@ -91,7 +104,7 @@ RUN export ARCH=$(echo ${TARGETPLATFORM} | cut -d / -f2) \
|
|||||||
|
|
||||||
VOLUME /var/lib/docker
|
VOLUME /var/lib/docker
|
||||||
|
|
||||||
COPY patched /runner/patched
|
COPY patched $RUNNER_ASSETS_DIR/patched
|
||||||
|
|
||||||
# No group definition, as that makes it harder to run docker.
|
# No group definition, as that makes it harder to run docker.
|
||||||
USER runner
|
USER runner
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ else
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -n "${RUNNER_WORKDIR}" ]; then
|
||||||
|
WORKDIR_ARG="--work ${RUNNER_WORKDIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -n "${RUNNER_LABELS}" ]; then
|
if [ -n "${RUNNER_LABELS}" ]; then
|
||||||
LABEL_ARG="--labels ${RUNNER_LABELS}"
|
LABEL_ARG="--labels ${RUNNER_LABELS}"
|
||||||
fi
|
fi
|
||||||
@@ -40,8 +44,20 @@ if [ -z "${RUNNER_REPO}" ] && [ -n "${RUNNER_ORG}" ] && [ -n "${RUNNER_GROUP}" ]
|
|||||||
RUNNER_GROUP_ARG="--runnergroup ${RUNNER_GROUP}"
|
RUNNER_GROUP_ARG="--runnergroup ${RUNNER_GROUP}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Hack due to https://github.com/summerwind/actions-runner-controller/issues/252#issuecomment-758338483
|
||||||
|
if [ ! -d /runner ]; then
|
||||||
|
echo "/runner should be an emptyDir mount. Please fix the pod spec." 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo chown -R runner:docker /runner
|
||||||
|
mv /runnertmp/* /runner/
|
||||||
|
|
||||||
cd /runner
|
cd /runner
|
||||||
./config.sh --unattended --replace --name "${RUNNER_NAME}" --url "${GITHUB_URL}${ATTACH}" --token "${RUNNER_TOKEN}" ${RUNNER_GROUP_ARG} ${LABEL_ARG}
|
./config.sh --unattended --replace --name "${RUNNER_NAME}" --url "${GITHUB_URL}${ATTACH}" --token "${RUNNER_TOKEN}" ${RUNNER_GROUP_ARG} ${LABEL_ARG} ${WORKDIR_ARG}
|
||||||
|
mkdir ./externals
|
||||||
|
# Hack due to the DinD volumes
|
||||||
|
mv ./externalstmp/* ./externals/
|
||||||
|
|
||||||
for f in runsvc.sh RunnerService.js; do
|
for f in runsvc.sh RunnerService.js; do
|
||||||
diff {bin,patched}/${f} || :
|
diff {bin,patched}/${f} || :
|
||||||
|
|||||||
Reference in New Issue
Block a user