# Gitea runner controller quick start


# Gitea runner controller quick start

&gt; 本文已过时，请参考官方文档。[官方文档](https://docs.gitea.com/enterprise/features/actions-runner-controller)

`runner-controller`是gitea公司为gitea企业版量身定制的一套k8s控制器，可以实现runner自动伸缩等功能。

## 本教程为快速入门教程，不适用于生产环境。本教程主要从gitea企业版安装和k8s部署 `runner-controller` 两个方面进行简单指导，也是最小化部署教程，仅供参考。

## 必要条件

拥有一套 amd64 架构的k8s集群和安装有docker和docker compose, 还有必须确保你的网络可以无障碍访问github、docker等外网。

## 安装gitea-ee（gitea 企业版）
gitea企业版使用docker compose部署，以下展示的为最小配置的docker-compose文件， 使用sqlite作为数据库：

创建一个`docker-compose.yml`文件输入以下内容，
```docker-compose
version: &#34;3&#34;

networks:
  gitea:
    external: false

services:
  server:
    image: commitgo/gitea-ee:latest
    container_name: gitea
    environment:
      - USER_UID=1000
      - USER_GID=1000
    restart: always
    networks:
      - gitea
    volumes:
      - ./gitea:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - &#34;3000:3000&#34;
      - &#34;2222:22&#34;
```
使用`docker compose up -d`启动一个gitea实例。

在浏览器输入你部署gitea实例主机的ip:port, 数据库类型选择`sqlite3`其他选项默认就好了，直接点击`install gitea`，稍等片刻gitea就安装完成。接着打开注册页输入自己的用户信息进行注册，第一个注册用户即为gitea的管理员账号。



## 使用license激活gitea企业版
使用上一步注册的账号进行登录，打开 `Site Administration` -&gt; `License`, 将`Instance ID`记录下来，等会申请license需要用到。

去`https://customers.gitea.com/`网站申请试用license，需要使用gitea.com上的账号授权登录。

点击`Start free trial`开始申请试用license，接着点击`My Gitea Enterprise is ready`，在`Instance ID`输入之前记录下来的ID，`Issued To`照抄上面绿色背景里的`Issued To`就可以，点击`Submit`提交使用申请，提交申请后gitea会直接给你分发一个license，可以将license下载下来保存，或者直接点击复制按钮。

打开`Site Administration` -&gt; `License`，将申请到的license粘贴到`Submit license`输入框，然后点击`Submit`就算完成激活工作了。


## 部署runner controller
第一步，先获取Runner的`registration token`，打开`Site Administration` -&gt; `Actions` -&gt; `Runners` -&gt; `Create new runner`,将`registration token`记录下来，等会需要用到。

第二步，部署`Local Path Provisioner`，使用以下命令apply即可。
```shell
kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.31/deploy/local-path-storage.yaml
```

第三步，部署runner controller。
创建`install.yml`文件，输入一下内容：
```yml
apiVersion: v1
kind: Namespace
metadata:
  labels:
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/name: runner-controller
    control-plane: controller-manager
  name: runner-controller-system
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
    controller-gen.kubebuilder.io/version: v0.16.1
  name: runners.gitea.com
spec:
  group: gitea.com
  names:
    kind: Runner
    listKind: RunnerList
    plural: runners
    singular: runner
  scope: Namespaced
  versions:
  - name: v1
    schema:
      openAPIV3Schema:
        description: Runner is the Schema for the runners API
        properties:
          apiVersion:
            description: |-
              APIVersion defines the versioned schema of this representation of an object.
              Servers should convert recognized schemas to the latest internal value, and
              may reject unrecognized values.
              More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
            type: string
          kind:
            description: |-
              Kind is a string value representing the REST resource this object represents.
              Servers may infer this from the endpoint the client submits requests to.
              Cannot be updated.
              In CamelCase.
              More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
            type: string
          metadata:
            type: object
          spec:
            description: RunnerSpec defines the desired state of Runner
            properties:
              gitea:
                description: Gitea is the Gitea spec
                properties:
                  instanceUrl:
                    description: InstanceUrl is the URL of the Gitea instance
                    format: url
                    type: string
                  registrationToken:
                    description: RegistrationToken is the registration token of the
                      runner
                    type: string
                required:
                - instanceUrl
                - registrationToken
                type: object
              runtime:
                default:
                  image: gitea/act_runner:nightly-dind
                  labels:
                    ubuntu-20.04: docker://gitea/runner-images:ubuntu-20.04
                    ubuntu-22.04: docker://gitea/runner-images:ubuntu-22.04
                    ubuntu-latest: docker://gitea/runner-images:ubuntu-latest
                description: Runtime is the runtime spec
                properties:
                  image:
                    default: gitea/act_runner:nightly-dind
                    description: Image is the image of the runner
                    type: string
                  labels:
                    additionalProperties:
                      type: string
                    default:
                      ubuntu-20.04: docker://gitea/runner-images:ubuntu-20.04
                      ubuntu-22.04: docker://gitea/runner-images:ubuntu-22.04
                      ubuntu-latest: docker://gitea/runner-images:ubuntu-latest
                    description: Labels is the labels of the runner
                    type: object
                required:
                - labels
                type: object
              scalability:
                default:
                  cpuRequest: &#34;2&#34;
                  maxSize: 10
                  memoryRequest: 4Gi
                description: Scalability is the scalability spec
                properties:
                  cpuRequest:
                    anyOf:
                    - type: integer
                    - type: string
                    default: &#34;2&#34;
                    description: CpuRequest is the CPU request of each runner
                    pattern: ^(\&#43;|-)?(([0-9]&#43;(\.[0-9]*)?)|(\.[0-9]&#43;))(([KMGTPE]i)|[numkMGTPE]|([eE](\&#43;|-)?(([0-9]&#43;(\.[0-9]*)?)|(\.[0-9]&#43;))))?$
                    x-kubernetes-int-or-string: true
                  maxSize:
                    default: 10
                    description: MaxSize is the maximum size of the runner
                    maximum: 9999
                    minimum: 1
                    type: integer
                  memoryRequest:
                    anyOf:
                    - type: integer
                    - type: string
                    default: 4Gi
                    description: MemoryRequest is the memory request of each runner
                    pattern: ^(\&#43;|-)?(([0-9]&#43;(\.[0-9]*)?)|(\.[0-9]&#43;))(([KMGTPE]i)|[numkMGTPE]|([eE](\&#43;|-)?(([0-9]&#43;(\.[0-9]*)?)|(\.[0-9]&#43;))))?$
                    x-kubernetes-int-or-string: true
                type: object
              storage:
                default:
                  cacheServerVolumeSize: 500Gi
                  cacheVolumeSize: 100Gi
                  className: standard
                  dataVolumeSize: 100Mi
                description: Storage is the storage spec
                properties:
                  cacheServerVolumeSize:
                    anyOf:
                    - type: integer
                    - type: string
                    default: 500Gi
                    description: CacheServerVolumeSize is the size of the cache server
                      volume
                    pattern: ^(\&#43;|-)?(([0-9]&#43;(\.[0-9]*)?)|(\.[0-9]&#43;))(([KMGTPE]i)|[numkMGTPE]|([eE](\&#43;|-)?(([0-9]&#43;(\.[0-9]*)?)|(\.[0-9]&#43;))))?$
                    x-kubernetes-int-or-string: true
                  cacheVolumeSize:
                    anyOf:
                    - type: integer
                    - type: string
                    default: 100Gi
                    description: CacheVolumeSize is the size of the cache volume
                    pattern: ^(\&#43;|-)?(([0-9]&#43;(\.[0-9]*)?)|(\.[0-9]&#43;))(([KMGTPE]i)|[numkMGTPE]|([eE](\&#43;|-)?(([0-9]&#43;(\.[0-9]*)?)|(\.[0-9]&#43;))))?$
                    x-kubernetes-int-or-string: true
                  className:
                    default: standard
                    description: ClassName is the storage class name
                    type: string
                  dataVolumeSize:
                    anyOf:
                    - type: integer
                    - type: string
                    default: 100Mi
                    description: DataVolumeSize is the size of the data volume
                    pattern: ^(\&#43;|-)?(([0-9]&#43;(\.[0-9]*)?)|(\.[0-9]&#43;))(([KMGTPE]i)|[numkMGTPE]|([eE](\&#43;|-)?(([0-9]&#43;(\.[0-9]*)?)|(\.[0-9]&#43;))))?$
                    x-kubernetes-int-or-string: true
                type: object
            required:
            - gitea
            type: object
          status:
            description: RunnerStatus defines the observed state of Runner
            properties:
              targetSize:
                type: integer
              targetSizeUpdatedAt:
                format: date-time
                type: string
            required:
            - targetSize
            - targetSizeUpdatedAt
            type: object
        type: object
    served: true
    storage: true
    subresources:
      status: {}
---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/name: runner-controller
  name: runner-controller-controller-manager
  namespace: runner-controller-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  labels:
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/name: runner-controller
  name: runner-controller-leader-election-role
  namespace: runner-controller-system
rules:
- apiGroups:
  - &#34;&#34;
  resources:
  - configmaps
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
- apiGroups:
  - coordination.k8s.io
  resources:
  - leases
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
- apiGroups:
  - &#34;&#34;
  resources:
  - events
  verbs:
  - create
  - patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: runner-controller-manager-role
rules:
- apiGroups:
  - &#34;&#34;
  resources:
  - configmaps
  - events
  - persistentvolumeclaims
  - persistentvolumes
  - pods
  - services
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - gitea.com
  resources:
  - runners
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - gitea.com
  resources:
  - runners/finalizers
  verbs:
  - update
- apiGroups:
  - gitea.com
  resources:
  - runners/status
  verbs:
  - get
  - patch
  - update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: runner-controller-metrics-auth-role
rules:
- apiGroups:
  - authentication.k8s.io
  resources:
  - tokenreviews
  verbs:
  - create
- apiGroups:
  - authorization.k8s.io
  resources:
  - subjectaccessreviews
  verbs:
  - create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: runner-controller-metrics-reader
rules:
- nonResourceURLs:
  - /metrics
  verbs:
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/name: runner-controller
  name: runner-controller-runner-editor-role
rules:
- apiGroups:
  - gitea.com
  resources:
  - runners
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - gitea.com
  resources:
  - runners/status
  verbs:
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/name: runner-controller
  name: runner-controller-runner-viewer-role
rules:
- apiGroups:
  - gitea.com
  resources:
  - runners
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - gitea.com
  resources:
  - runners/status
  verbs:
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  labels:
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/name: runner-controller
  name: runner-controller-leader-election-rolebinding
  namespace: runner-controller-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: runner-controller-leader-election-role
subjects:
- kind: ServiceAccount
  name: runner-controller-controller-manager
  namespace: runner-controller-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/name: runner-controller
  name: runner-controller-manager-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: runner-controller-manager-role
subjects:
- kind: ServiceAccount
  name: runner-controller-controller-manager
  namespace: runner-controller-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: runner-controller-metrics-auth-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: runner-controller-metrics-auth-role
subjects:
- kind: ServiceAccount
  name: runner-controller-controller-manager
  namespace: runner-controller-system
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/name: runner-controller
    control-plane: controller-manager
  name: runner-controller-controller-manager-metrics-service
  namespace: runner-controller-system
spec:
  ports:
  - name: https
    port: 8443
    protocol: TCP
    targetPort: 8443
  selector:
    control-plane: controller-manager
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/name: runner-controller
    control-plane: controller-manager
  name: runner-controller-controller-manager
  namespace: runner-controller-system
spec:
  replicas: 1
  selector:
    matchLabels:
      control-plane: controller-manager
  template:
    metadata:
      annotations:
        kubectl.kubernetes.io/default-container: manager
      labels:
        control-plane: controller-manager
    spec:
      containers:
      - args:
        - --metrics-bind-address=:8443
        - --leader-elect
        - --health-probe-bind-address=:8081
        command:
        - /manager
        image: commitgo/runner-controller:v0.3.1
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8081
          initialDelaySeconds: 15
          periodSeconds: 20
        name: manager
        readinessProbe:
          httpGet:
            path: /readyz
            port: 8081
          initialDelaySeconds: 5
          periodSeconds: 10
        resources:
          limits:
            cpu: 500m
            memory: 128Mi
          requests:
            cpu: 10m
            memory: 64Mi
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
      securityContext:
        runAsNonRoot: true
      serviceAccountName: runner-controller-controller-manager
      terminationGracePeriodSeconds: 10
```

创建`example.yml`文件，输入以下内容：
```yml
apiVersion: gitea.com/v1
kind: Runner
metadata:
  labels:
    app.kubernetes.io/name: runner-controller
    app.kubernetes.io/managed-by: kustomize
  name: &#34;gitea-runner&#34; # TODO, like my-runner
spec:
  gitea:
    instanceUrl: &#34;&lt;填入gitea实例地址&gt;&#34; # TODO, like https://mygitea.com/
    registrationToken: &#34;&lt;填入第一步获取到的registration token&gt;&#34; # TODO, it&#39;s the same token to register runners
  runtime:
    labels:
      ubuntu-latest: docker://gitea/runner-images:ubuntu-latest
      ubuntu-22.04: docker://gitea/runner-images:ubuntu-22.04
      ubuntu-20.04: docker://gitea/runner-images:ubuntu-20.04
  storage:
    className: &#34;local-path&#34; # TODO, it should be real storage class in your k8s cluster
  scalability:
    maxSize: 10
    cpuRequest: 4
    memoryRequest: 8Gi
```

应用`runner controller`配置, 
```shell
kubectl apply -f install.yml
kubectl apply -f example.yml
```

## 测试runner

创建一个仓库，接着在该仓库创建`.gitea/workflows/test.yml`文件，输入一下内容：
```yml
name: Gitea Actions Demo
run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀
on: [push]

jobs:
  Explore-Gitea-Actions:
    runs-on: ubuntu-latest
    steps:
      - run: echo &#34;🎉 The job was automatically triggered by a ${{ gitea.event_name }} event.&#34;
      - run: echo &#34;🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!&#34;
      - run: echo &#34;🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}.&#34;
      - name: Check out repository code
        uses: actions/checkout@v4
      - run: echo &#34;💡 The ${{ gitea.repository }} repository has been cloned to the runner.&#34;
      - run: echo &#34;🖥️ The workflow is now ready to test your code on the runner.&#34;
      - name: List files in the repository
        run: |
          ls ${{ gitea.workspace }}
      - run: echo &#34;🍏 This job&#39;s status is ${{ job.status }}.&#34;
```

在该仓库的`Actions` tab里查看运行结果。


---

> 作者: hiifong  
> URL: https://f.style/runner-controller/  

