mirror of
https://github.com/actions/actions-runner-controller.git
synced 2025-12-11 20:21:02 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2d3ca672f | ||
|
|
829a167303 | ||
|
|
c66916a4ee | ||
|
|
f5c8a0e655 |
13
README.md
13
README.md
@@ -13,7 +13,7 @@ This controller operates self-hosted runners for GitHub Actions on your Kubernet
|
|||||||
First, install *actions-runner-controller* with a manifest file. This will create a *actions-runner-system* namespace in your Kubernetes and deploy the required resources.
|
First, install *actions-runner-controller* with a manifest file. This will create a *actions-runner-system* namespace in your Kubernetes and deploy the required resources.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ kubectl -f https://github.com/summerwind/actions-runner-controller/releases/download/latest/actions-runner-controller.yaml
|
$ kubectl apply -f https://github.com/summerwind/actions-runner-controller/releases/latest/download/actions-runner-controller.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Set your access token of GitHub to the secret. `${GITHUB_TOKEN}` is the value you must replace with your access token. This token is used to register Self-hosted runner by *actions-runner-controller*.
|
Set your access token of GitHub to the secret. `${GITHUB_TOKEN}` is the value you must replace with your access token. This token is used to register Self-hosted runner by *actions-runner-controller*.
|
||||||
@@ -27,9 +27,7 @@ $ kubectl create secret generic controller-manager --from-literal=github_token=$
|
|||||||
To launch Self-hosted runner, you need to create a manifest file includes *Runner* resource as follows. This example launches a self-hosted runner with name *example-runner* for the *summerwind/actions-runner-controller* repository.
|
To launch Self-hosted runner, you need to create a manifest file includes *Runner* resource as follows. This example launches a self-hosted runner with name *example-runner* for the *summerwind/actions-runner-controller* repository.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ vim runner.yaml
|
# runner.yaml
|
||||||
```
|
|
||||||
```
|
|
||||||
apiVersion: actions.summerwind.dev/v1alpha1
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
kind: Runner
|
kind: Runner
|
||||||
metadata:
|
metadata:
|
||||||
@@ -42,14 +40,15 @@ Apply the created manifest file to your Kubernetes.
|
|||||||
|
|
||||||
```
|
```
|
||||||
$ kubectl apply -f runner.yaml
|
$ kubectl apply -f runner.yaml
|
||||||
|
runner.actions.summerwind.dev/example-runner created
|
||||||
```
|
```
|
||||||
|
|
||||||
You can see that the Runner resource has been created.
|
You can see that the Runner resource has been created.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ kubectl get runners
|
$ kubectl get runners
|
||||||
NAME AGE
|
NAME REPOSITORY STATUS
|
||||||
example-runner 1m
|
example-runner summerwind/actions-runner-controller Running
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also see that the runner pod has been running.
|
You can also see that the runner pod has been running.
|
||||||
@@ -64,4 +63,4 @@ The runner you created has been registerd to your repository.
|
|||||||
|
|
||||||
<img width="756" alt="Actions tab in your repository settings" src="https://user-images.githubusercontent.com/230145/73618667-8cbf9700-466c-11ea-80b6-c67e6d3f70e7.png">
|
<img width="756" alt="Actions tab in your repository settings" src="https://user-images.githubusercontent.com/230145/73618667-8cbf9700-466c-11ea-80b6-c67e6d3f70e7.png">
|
||||||
|
|
||||||
Now your can use your self-hosted runner. See the [documentation](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/using-self-hosted-runners-in-a-workflow) on how to run a job with it.
|
Now your can use your self-hosted runner. See the [official documentation](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/using-self-hosted-runners-in-a-workflow) on how to run a job with it.
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,6 +29,9 @@ type RunnerSpec struct {
|
|||||||
|
|
||||||
// +optional
|
// +optional
|
||||||
Image string `json:"image"`
|
Image string `json:"image"`
|
||||||
|
|
||||||
|
// +optional
|
||||||
|
Env []corev1.EnvVar `json:"env"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunnerStatus defines the observed state of Runner
|
// RunnerStatus defines the observed state of Runner
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ limitations under the License.
|
|||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ func (in *Runner) DeepCopyInto(out *Runner) {
|
|||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
out.Spec = in.Spec
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
in.Status.DeepCopyInto(&out.Status)
|
in.Status.DeepCopyInto(&out.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +87,13 @@ func (in *RunnerList) DeepCopyObject() runtime.Object {
|
|||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *RunnerSpec) DeepCopyInto(out *RunnerSpec) {
|
func (in *RunnerSpec) DeepCopyInto(out *RunnerSpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
if in.Env != nil {
|
||||||
|
in, out := &in.Env, &out.Env
|
||||||
|
*out = make([]v1.EnvVar, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
|
|||||||
@@ -43,6 +43,103 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
description: RunnerSpec defines the desired state of Runner
|
description: RunnerSpec defines the desired state of Runner
|
||||||
properties:
|
properties:
|
||||||
|
env:
|
||||||
|
items:
|
||||||
|
description: EnvVar represents an environment variable present in
|
||||||
|
a Container.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name of the environment variable. Must be a C_IDENTIFIER.
|
||||||
|
type: string
|
||||||
|
value:
|
||||||
|
description: 'Variable references $(VAR_NAME) are expanded using
|
||||||
|
the previous defined environment variables in the container
|
||||||
|
and any service environment variables. If a variable cannot
|
||||||
|
be resolved, the reference in the input string will be unchanged.
|
||||||
|
The $(VAR_NAME) syntax can be escaped with a double $$, ie:
|
||||||
|
$$(VAR_NAME). Escaped references will never be expanded, regardless
|
||||||
|
of whether the variable exists or not. Defaults to "".'
|
||||||
|
type: string
|
||||||
|
valueFrom:
|
||||||
|
description: Source for the environment variable's value. Cannot
|
||||||
|
be used if value is not empty.
|
||||||
|
properties:
|
||||||
|
configMapKeyRef:
|
||||||
|
description: Selects a key of a ConfigMap.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: The key to select.
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||||
|
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||||
|
type: string
|
||||||
|
optional:
|
||||||
|
description: Specify whether the ConfigMap or its key
|
||||||
|
must be defined
|
||||||
|
type: boolean
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
type: object
|
||||||
|
fieldRef:
|
||||||
|
description: 'Selects a field of the pod: supports metadata.name,
|
||||||
|
metadata.namespace, metadata.labels, metadata.annotations,
|
||||||
|
spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP.'
|
||||||
|
properties:
|
||||||
|
apiVersion:
|
||||||
|
description: Version of the schema the FieldPath is written
|
||||||
|
in terms of, defaults to "v1".
|
||||||
|
type: string
|
||||||
|
fieldPath:
|
||||||
|
description: Path of the field to select in the specified
|
||||||
|
API version.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- fieldPath
|
||||||
|
type: object
|
||||||
|
resourceFieldRef:
|
||||||
|
description: 'Selects a resource of the container: only resources
|
||||||
|
limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage,
|
||||||
|
requests.cpu, requests.memory and requests.ephemeral-storage)
|
||||||
|
are currently supported.'
|
||||||
|
properties:
|
||||||
|
containerName:
|
||||||
|
description: 'Container name: required for volumes, optional
|
||||||
|
for env vars'
|
||||||
|
type: string
|
||||||
|
divisor:
|
||||||
|
description: Specifies the output format of the exposed
|
||||||
|
resources, defaults to "1"
|
||||||
|
type: string
|
||||||
|
resource:
|
||||||
|
description: 'Required: resource to select'
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- resource
|
||||||
|
type: object
|
||||||
|
secretKeyRef:
|
||||||
|
description: Selects a key of a secret in the pod's namespace
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: The key of the secret to select from. Must
|
||||||
|
be a valid secret key.
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||||
|
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||||
|
type: string
|
||||||
|
optional:
|
||||||
|
description: Specify whether the Secret or its key must
|
||||||
|
be defined
|
||||||
|
type: boolean
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
image:
|
image:
|
||||||
type: string
|
type: string
|
||||||
repository:
|
repository:
|
||||||
|
|||||||
@@ -334,19 +334,7 @@ func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) {
|
|||||||
runnerImage = r.RunnerImage
|
runnerImage = r.RunnerImage
|
||||||
}
|
}
|
||||||
|
|
||||||
pod := corev1.Pod{
|
env := []corev1.EnvVar{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: runner.Name,
|
|
||||||
Namespace: runner.Namespace,
|
|
||||||
},
|
|
||||||
Spec: corev1.PodSpec{
|
|
||||||
RestartPolicy: "OnFailure",
|
|
||||||
Containers: []corev1.Container{
|
|
||||||
{
|
|
||||||
Name: containerName,
|
|
||||||
Image: runnerImage,
|
|
||||||
ImagePullPolicy: "Always",
|
|
||||||
Env: []corev1.EnvVar{
|
|
||||||
{
|
{
|
||||||
Name: "RUNNER_NAME",
|
Name: "RUNNER_NAME",
|
||||||
Value: runner.Name,
|
Value: runner.Name,
|
||||||
@@ -359,7 +347,22 @@ func (r *RunnerReconciler) newPod(runner v1alpha1.Runner) (corev1.Pod, error) {
|
|||||||
Name: "RUNNER_TOKEN",
|
Name: "RUNNER_TOKEN",
|
||||||
Value: runner.Status.Registration.Token,
|
Value: runner.Status.Registration.Token,
|
||||||
},
|
},
|
||||||
|
}
|
||||||
|
env = append(env, runner.Spec.Env...)
|
||||||
|
|
||||||
|
pod := corev1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: runner.Name,
|
||||||
|
Namespace: runner.Namespace,
|
||||||
},
|
},
|
||||||
|
Spec: corev1.PodSpec{
|
||||||
|
RestartPolicy: "OnFailure",
|
||||||
|
Containers: []corev1.Container{
|
||||||
|
{
|
||||||
|
Name: containerName,
|
||||||
|
Image: runnerImage,
|
||||||
|
ImagePullPolicy: "Always",
|
||||||
|
Env: env,
|
||||||
VolumeMounts: []corev1.VolumeMount{
|
VolumeMounts: []corev1.VolumeMount{
|
||||||
{
|
{
|
||||||
Name: "docker",
|
Name: "docker",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ RUN apt update \
|
|||||||
&& tar zxvf docker.tgz \
|
&& tar zxvf docker.tgz \
|
||||||
&& install -o root -g root -m 755 docker/docker /usr/local/bin/docker \
|
&& install -o root -g root -m 755 docker/docker /usr/local/bin/docker \
|
||||||
&& rm -rf docker docker.tgz \
|
&& rm -rf docker docker.tgz \
|
||||||
|
&& curl -L -o /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.2/dumb-init_1.2.2_amd64 \
|
||||||
|
&& chmod +x /usr/local/bin/dumb-init \
|
||||||
&& adduser --disabled-password --gecos "" --uid 1000 runner
|
&& adduser --disabled-password --gecos "" --uid 1000 runner
|
||||||
|
|
||||||
RUN mkdir -p /runner \
|
RUN mkdir -p /runner \
|
||||||
@@ -21,4 +23,5 @@ RUN mkdir -p /runner \
|
|||||||
COPY entrypoint.sh /runner
|
COPY entrypoint.sh /runner
|
||||||
|
|
||||||
USER runner:runner
|
USER runner:runner
|
||||||
ENTRYPOINT ["/runner/entrypoint.sh"]
|
ENTRYPOINT ["/usr/local/bin/dumb-init", "--"]
|
||||||
|
CMD ["/runner/entrypoint.sh"]
|
||||||
|
|||||||
@@ -17,4 +17,6 @@ fi
|
|||||||
|
|
||||||
cd /runner
|
cd /runner
|
||||||
./config.sh --unattended --replace --name "${RUNNER_NAME}" --url "https://github.com/${RUNNER_REPO}" --token "${RUNNER_TOKEN}"
|
./config.sh --unattended --replace --name "${RUNNER_NAME}" --url "https://github.com/${RUNNER_REPO}" --token "${RUNNER_TOKEN}"
|
||||||
./run.sh --once
|
|
||||||
|
unset RUNNER_NAME RUNNER_REPO RUNNER_TOKEN
|
||||||
|
exec ./run.sh --once
|
||||||
|
|||||||
Reference in New Issue
Block a user