mirror of
https://gitea.com/gitea/act_runner.git
synced 2025-12-16 19:14:46 +00:00
Compare commits
10 Commits
69c55ee003
...
v0.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45bfe0a9b2 | ||
|
|
316534996a | ||
|
|
67b1363d25 | ||
|
|
946c41cf4f | ||
|
|
341d49a24d | ||
|
|
b21d476aca | ||
|
|
a29307a9d9 | ||
|
|
4bfbfec477 | ||
|
|
fed01c9807 | ||
|
|
a83f29d5a9 |
@@ -58,11 +58,6 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0 # all history for all branches and tags
|
||||
|
||||
- name: dockerfile lint check
|
||||
uses: https://github.com/hadolint/hadolint-action@v3.1.0
|
||||
with:
|
||||
dockerfile: Dockerfile
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
@@ -95,3 +90,16 @@ jobs:
|
||||
tags: |
|
||||
${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}
|
||||
|
||||
- name: Build and push dind-rootless
|
||||
uses: docker/build-push-action@v4
|
||||
env:
|
||||
ACTIONS_RUNTIME_TOKEN: '' # See https://gitea.com/gitea/act_runner/issues/119
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.rootless
|
||||
platforms: |
|
||||
linux/amd64
|
||||
linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}-dind-rootless
|
||||
|
||||
@@ -69,11 +69,6 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0 # all history for all branches and tags
|
||||
|
||||
- name: dockerfile lint check
|
||||
uses: https://github.com/hadolint/hadolint-action@v3.1.0
|
||||
with:
|
||||
dockerfile: Dockerfile
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
@@ -106,3 +101,18 @@ jobs:
|
||||
tags: |
|
||||
${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }}
|
||||
${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}
|
||||
|
||||
- name: Build and push dind-rootless
|
||||
uses: docker/build-push-action@v4
|
||||
env:
|
||||
ACTIONS_RUNTIME_TOKEN: '' # See https://gitea.com/gitea/act_runner/issues/119
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.rootless
|
||||
platforms: |
|
||||
linux/amd64
|
||||
linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }}-dind-rootless
|
||||
${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}-dind-rootless
|
||||
|
||||
@@ -36,7 +36,3 @@ jobs:
|
||||
run: make build
|
||||
- name: test
|
||||
run: make test
|
||||
- name: dockerfile lint check
|
||||
uses: https://github.com/hadolint/hadolint-action@v3.1.0
|
||||
with:
|
||||
dockerfile: Dockerfile
|
||||
|
||||
12
Dockerfile
12
Dockerfile
@@ -1,18 +1,16 @@
|
||||
FROM golang:1.20-alpine3.17 as builder
|
||||
FROM golang:1.20-alpine3.18 as builder
|
||||
# Do not remove `git` here, it is required for getting runner version when executing `make build`
|
||||
RUN apk add --no-cache make=4.3-r1 git=2.38.5-r0
|
||||
RUN apk add --no-cache make git
|
||||
|
||||
COPY . /opt/src/act_runner
|
||||
WORKDIR /opt/src/act_runner
|
||||
|
||||
RUN make clean && make build
|
||||
|
||||
FROM alpine:3.17
|
||||
RUN apk add --no-cache \
|
||||
git=2.38.5-r0 bash=5.2.15-r0 tini=0.19.0-r1 \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
FROM alpine:3.18
|
||||
RUN apk add --no-cache git bash tini
|
||||
|
||||
COPY --from=builder /opt/src/act_runner/act_runner /usr/local/bin/act_runner
|
||||
COPY run.sh /opt/act/run.sh
|
||||
COPY scripts/run.sh /opt/act/run.sh
|
||||
|
||||
ENTRYPOINT ["/sbin/tini","--","/opt/act/run.sh"]
|
||||
|
||||
24
Dockerfile.rootless
Normal file
24
Dockerfile.rootless
Normal file
@@ -0,0 +1,24 @@
|
||||
FROM golang:1.20-alpine3.18 as builder
|
||||
# Do not remove `git` here, it is required for getting runner version when executing `make build`
|
||||
RUN apk add --no-cache make git
|
||||
|
||||
COPY . /opt/src/act_runner
|
||||
WORKDIR /opt/src/act_runner
|
||||
|
||||
RUN make clean && make build
|
||||
|
||||
FROM docker:dind-rootless
|
||||
USER root
|
||||
RUN apk add --no-cache \
|
||||
git bash supervisor
|
||||
|
||||
COPY --from=builder /opt/src/act_runner/act_runner /usr/local/bin/act_runner
|
||||
COPY /scripts/supervisord.conf /etc/supervisord.conf
|
||||
COPY /scripts/run.sh /opt/act/run.sh
|
||||
COPY /scripts/rootless.sh /opt/act/rootless.sh
|
||||
|
||||
RUN mkdir /data \
|
||||
&& chown rootless:rootless /data
|
||||
|
||||
USER rootless
|
||||
ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
|
||||
4
Makefile
4
Makefile
@@ -19,6 +19,7 @@ GOFILES := $(shell find . -type f -name "*.go" -o -name "go.mod" ! -name "genera
|
||||
DOCKER_IMAGE ?= gitea/act_runner
|
||||
DOCKER_TAG ?= nightly
|
||||
DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)
|
||||
DOCKER_ROOTLESS_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)-dind-rootless
|
||||
|
||||
ifneq ($(shell uname), Darwin)
|
||||
EXTLDFLAGS = -extldflags "-static" $(null)
|
||||
@@ -69,7 +70,7 @@ GO_PACKAGES_TO_VET ?= $(filter-out gitea.com/gitea/act_runner/internal/pkg/clien
|
||||
|
||||
|
||||
TAGS ?=
|
||||
LDFLAGS ?= -X "gitea.com/gitea/act_runner/internal/pkg/ver.version=$(RELASE_VERSION)"
|
||||
LDFLAGS ?= -X "gitea.com/gitea/act_runner/internal/pkg/ver.version=v$(RELASE_VERSION)"
|
||||
|
||||
all: build
|
||||
|
||||
@@ -169,6 +170,7 @@ docker:
|
||||
ARG_DISABLE_CONTENT_TRUST=--disable-content-trust=false; \
|
||||
fi; \
|
||||
docker build $${ARG_DISABLE_CONTENT_TRUST} -t $(DOCKER_REF) .
|
||||
docker build $${ARG_DISABLE_CONTENT_TRUST} -t $(DOCKER_ROOTLESS_REF) -f Dockerfile.rootless .
|
||||
|
||||
clean:
|
||||
$(GO) clean -x -i ./...
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
## Usage Examples for `act_runner`
|
||||
# Usage Examples for `act_runner`
|
||||
|
||||
Here you will find usage and deployment examples that can be directly used in a Gitea setup. Please feel free to contribute!
|
||||
Welcome to our collection of usage and deployment examples specifically designed for Gitea setups. Whether you're a beginner or an experienced user, you'll find practical resources here that you can directly apply to enhance your Gitea experience. We encourage you to contribute your own insights and knowledge to make this collection even more comprehensive and valuable.
|
||||
|
||||
| Section | Description |
|
||||
|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| [`docker`](docker) | This section provides you with scripts and instructions tailored for running containers on a workstation or server where Docker is installed. It simplifies the process of setting up and managing your Gitea deployment using Docker. |
|
||||
| [`docker-compose`](docker-compose) | In this section, you'll discover examples demonstrating how to utilize docker-compose to efficiently handle your Gitea deployments. It offers a straightforward approach to managing multiple containerized components of your Gitea setup. |
|
||||
| [`kubernetes`](kubernetes) | If you're utilizing Kubernetes clusters for your infrastructure, this section is specifically designed for you. It presents examples and guidelines for configuring Gitea deployments within Kubernetes clusters, enabling you to leverage the scalability and flexibility of Kubernetes. |
|
||||
| [`vm`](vm) | This section is dedicated to examples that assist you in setting up Gitea on virtual or physical servers. Whether you're working with virtual machines or physical hardware, you'll find helpful resources to guide you through the deployment process. |
|
||||
|
||||
- [`docker`](docker)
|
||||
Contains scripts and instructions for running containers on a workstation or server with Docker installed.
|
||||
|
||||
- [`docker-compose`](docker-compose)
|
||||
Contains examples of using `docker-compose` to manage deployments.
|
||||
|
||||
- [`kubernetes`](kubernetes)
|
||||
Contains examples of setting up deployments in Kubernetes clusters.
|
||||
|
||||
- [`vm`](vm)
|
||||
Contains examples for setting up virtual or physical servers.
|
||||
We hope these resources provide you with valuable insights and solutions for your Gitea setup. Feel free to explore, contribute, and adapt these examples to suit your specific requirements.
|
||||
|
||||
@@ -6,3 +6,6 @@ Files in this directory:
|
||||
|
||||
- [`dind-docker.yaml`](dind-docker.yaml)
|
||||
How to create a Deployment and Persistent Volume for Kubernetes to act as a runner. The Docker credentials are re-generated each time the pod connects and does not need to be persisted.
|
||||
|
||||
- [`rootless-docker.yaml`](rootless-docker.yaml)
|
||||
How to create a rootless Deployment and Persistent Volume for Kubernetes to act as a runner. The Docker credentials are re-generated each time the pod connects and does not need to be persisted.
|
||||
|
||||
68
examples/kubernetes/rootless-docker.yaml
Normal file
68
examples/kubernetes/rootless-docker.yaml
Normal file
@@ -0,0 +1,68 @@
|
||||
kind: PersistentVolumeClaim
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: act-runner-vol
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
storageClassName: standard
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
token: << runner registration token goes here >>
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: runner-secret
|
||||
type: Opaque
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: act-runner
|
||||
name: act-runner
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: act-runner
|
||||
strategy: {}
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: act-runner
|
||||
spec:
|
||||
restartPolicy: Always
|
||||
volumes:
|
||||
- name: runner-data
|
||||
persistentVolumeClaim:
|
||||
claimName: act-runner-vol
|
||||
containers:
|
||||
- name: runner
|
||||
image: gitea/act_runner:nightly-dind-rootless
|
||||
imagePullPolicy: Always
|
||||
# command: ["sh", "-c", "while ! nc -z localhost 2376 </dev/null; do echo 'waiting for docker daemon...'; sleep 5; done; /sbin/tini -- /opt/act/run.sh"]
|
||||
env:
|
||||
- name: DOCKER_HOST
|
||||
value: tcp://localhost:2376
|
||||
- name: DOCKER_CERT_PATH
|
||||
value: /certs/client
|
||||
- name: DOCKER_TLS_VERIFY
|
||||
value: "1"
|
||||
- name: GITEA_INSTANCE_URL
|
||||
value: http://gitea-http.gitea.svc.cluster.local:3000
|
||||
- name: GITEA_RUNNER_REGISTRATION_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: runner-secret
|
||||
key: token
|
||||
securityContext:
|
||||
privileged: true
|
||||
volumeMounts:
|
||||
- name: runner-data
|
||||
mountPath: /data
|
||||
|
||||
4
go.mod
4
go.mod
@@ -3,7 +3,7 @@ module gitea.com/gitea/act_runner
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
code.gitea.io/actions-proto-go v0.2.1
|
||||
code.gitea.io/actions-proto-go v0.3.0
|
||||
code.gitea.io/gitea-vet v0.2.3-0.20230113022436-2b1561217fa5
|
||||
github.com/avast/retry-go/v4 v4.3.1
|
||||
github.com/bufbuild/connect-go v1.3.1
|
||||
@@ -87,4 +87,4 @@ require (
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/nektos/act => gitea.com/gitea/act v0.245.2-0.20230516060355-9283cfc9b166
|
||||
replace github.com/nektos/act => gitea.com/gitea/act v0.245.2-0.20230606002131-6ce5c93cc815
|
||||
|
||||
8
go.sum
8
go.sum
@@ -1,9 +1,9 @@
|
||||
code.gitea.io/actions-proto-go v0.2.1 h1:ToMN/8thz2q10TuCq8dL2d8mI+/pWpJcHCvG+TELwa0=
|
||||
code.gitea.io/actions-proto-go v0.2.1/go.mod h1:00ys5QDo1iHN1tHNvvddAcy2W/g+425hQya1cCSvq9A=
|
||||
code.gitea.io/actions-proto-go v0.3.0 h1:9Tvg8+TaaCXPKi6EnWl9vVgs2VZsj1Cs5afnsHa4AmM=
|
||||
code.gitea.io/actions-proto-go v0.3.0/go.mod h1:00ys5QDo1iHN1tHNvvddAcy2W/g+425hQya1cCSvq9A=
|
||||
code.gitea.io/gitea-vet v0.2.3-0.20230113022436-2b1561217fa5 h1:daBEK2GQeqGikJESctP5Cu1i33z5ztAD4kyQWiw185M=
|
||||
code.gitea.io/gitea-vet v0.2.3-0.20230113022436-2b1561217fa5/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
|
||||
gitea.com/gitea/act v0.245.2-0.20230516060355-9283cfc9b166 h1:hvyzFmxDmdSZBd8S2+r8VqPSK9eihTD2SrTBAvwgYsA=
|
||||
gitea.com/gitea/act v0.245.2-0.20230516060355-9283cfc9b166/go.mod h1:1ffiGQZAZCLuk9QEBDdbRuQj1GL4uAQk6GNNtcEnPmI=
|
||||
gitea.com/gitea/act v0.245.2-0.20230606002131-6ce5c93cc815 h1:u4rHwJLJnH6mej1BjEc4iubwknVeJmRVq9xQP9cAMeQ=
|
||||
gitea.com/gitea/act v0.245.2-0.20230606002131-6ce5c93cc815/go.mod h1:1ffiGQZAZCLuk9QEBDdbRuQj1GL4uAQk6GNNtcEnPmI=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bufbuild/connect-go"
|
||||
"github.com/mattn/go-isatty"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -43,8 +44,13 @@ func runDaemon(ctx context.Context, configFile *string) func(cmd *cobra.Command,
|
||||
return fmt.Errorf("failed to load registration file: %w", err)
|
||||
}
|
||||
|
||||
lbls := reg.Labels
|
||||
if len(cfg.Runner.Labels) > 0 {
|
||||
lbls = cfg.Runner.Labels
|
||||
}
|
||||
|
||||
ls := labels.Labels{}
|
||||
for _, l := range reg.Labels {
|
||||
for _, l := range lbls {
|
||||
label, err := labels.Parse(l)
|
||||
if err != nil {
|
||||
log.WithError(err).Warnf("ignored invalid label %q", l)
|
||||
@@ -71,6 +77,24 @@ func runDaemon(ctx context.Context, configFile *string) func(cmd *cobra.Command,
|
||||
)
|
||||
|
||||
runner := run.NewRunner(cfg, reg, cli)
|
||||
// declare the labels of the runner before fetching tasks
|
||||
resp, err := runner.Declare(ctx, ls.Names())
|
||||
if err != nil && connect.CodeOf(err) == connect.CodeUnimplemented {
|
||||
// Gitea instance is older version. skip declare step.
|
||||
log.Warn("Because the Gitea instance is an old version, skip declare labels and version.")
|
||||
} else if err != nil {
|
||||
log.WithError(err).Error("fail to invoke Declare")
|
||||
return err
|
||||
} else {
|
||||
log.Infof("runner: %s, with version: %s, with labels: %v, declare successfully",
|
||||
resp.Msg.Runner.Name, resp.Msg.Runner.Version, resp.Msg.Runner.Labels)
|
||||
// if declare successfully, override the labels in the.runner file with valid labels in the config file (if specified)
|
||||
reg.Labels = ls.ToStrings()
|
||||
if err := config.SaveRegistration(cfg.Runner.File, reg); err != nil {
|
||||
return fmt.Errorf("failed to save runner config: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
poller := poll.New(cfg, cli, runner)
|
||||
|
||||
poller.Poll(ctx)
|
||||
|
||||
@@ -39,7 +39,7 @@ type executeArgs struct {
|
||||
envs []string
|
||||
envfile string
|
||||
secrets []string
|
||||
defaultActionsUrl string
|
||||
defaultActionsUrls []string
|
||||
insecureSecrets bool
|
||||
privileged bool
|
||||
usernsMode string
|
||||
@@ -403,10 +403,10 @@ func runExec(ctx context.Context, execArgs *executeArgs) func(cmd *cobra.Command
|
||||
NoSkipCheckout: execArgs.noSkipCheckout,
|
||||
// PresetGitHubContext: preset,
|
||||
// EventJSON: string(eventJSON),
|
||||
ContainerNamePrefix: fmt.Sprintf("GITEA-ACTIONS-TASK-%s", eventName),
|
||||
ContainerMaxLifetime: maxLifetime,
|
||||
ContainerNetworkMode: container.NetworkMode(execArgs.network),
|
||||
DefaultActionInstance: execArgs.defaultActionsUrl,
|
||||
ContainerNamePrefix: fmt.Sprintf("GITEA-ACTIONS-TASK-%s", eventName),
|
||||
ContainerMaxLifetime: maxLifetime,
|
||||
ContainerNetworkMode: container.NetworkMode(execArgs.network),
|
||||
DefaultActionsURLs: execArgs.defaultActionsUrls,
|
||||
PlatformPicker: func(_ []string) string {
|
||||
return execArgs.image
|
||||
},
|
||||
@@ -470,7 +470,7 @@ func loadExecCmd(ctx context.Context) *cobra.Command {
|
||||
execCmd.PersistentFlags().StringVarP(&execArg.artifactServerPath, "artifact-server-path", "", ".", "Defines the path where the artifact server stores uploads and retrieves downloads from. If not specified the artifact server will not start.")
|
||||
execCmd.PersistentFlags().StringVarP(&execArg.artifactServerAddr, "artifact-server-addr", "", "", "Defines the address where the artifact server listens")
|
||||
execCmd.PersistentFlags().StringVarP(&execArg.artifactServerPort, "artifact-server-port", "", "34567", "Defines the port where the artifact server listens (will only bind to localhost).")
|
||||
execCmd.PersistentFlags().StringVarP(&execArg.defaultActionsUrl, "default-actions-url", "", "https://gitea.com", "Defines the default url of action instance.")
|
||||
execCmd.PersistentFlags().StringArrayVarP(&execArg.defaultActionsUrls, "default-actions-url", "", []string{"https://gitea.com", "https://github.com"}, "Defines the default url list of action instance.")
|
||||
execCmd.PersistentFlags().BoolVarP(&execArg.noSkipCheckout, "no-skip-checkout", "", false, "Do not skip actions/checkout")
|
||||
execCmd.PersistentFlags().BoolVarP(&execArg.debug, "debug", "d", false, "enable debug log")
|
||||
execCmd.PersistentFlags().BoolVarP(&execArg.dryrun, "dryrun", "n", false, "dryrun mode")
|
||||
|
||||
@@ -85,7 +85,7 @@ const (
|
||||
StageInputInstance
|
||||
StageInputToken
|
||||
StageInputRunnerName
|
||||
StageInputCustomLabels
|
||||
StageInputLabels
|
||||
StageWaitingForRegistration
|
||||
StageExit
|
||||
)
|
||||
@@ -101,7 +101,7 @@ type registerInputs struct {
|
||||
InstanceAddr string
|
||||
Token string
|
||||
RunnerName string
|
||||
CustomLabels []string
|
||||
Labels []string
|
||||
}
|
||||
|
||||
func (r *registerInputs) validate() error {
|
||||
@@ -111,8 +111,8 @@ func (r *registerInputs) validate() error {
|
||||
if r.Token == "" {
|
||||
return fmt.Errorf("token is empty")
|
||||
}
|
||||
if len(r.CustomLabels) > 0 {
|
||||
return validateLabels(r.CustomLabels)
|
||||
if len(r.Labels) > 0 {
|
||||
return validateLabels(r.Labels)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -126,7 +126,7 @@ func validateLabels(ls []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *registerInputs) assignToNext(stage registerStage, value string) registerStage {
|
||||
func (r *registerInputs) assignToNext(stage registerStage, value string, cfg *config.Config) registerStage {
|
||||
// must set instance address and token.
|
||||
// if empty, keep current stage.
|
||||
if stage == StageInputInstance || stage == StageInputToken {
|
||||
@@ -154,16 +154,33 @@ func (r *registerInputs) assignToNext(stage registerStage, value string) registe
|
||||
return StageInputRunnerName
|
||||
case StageInputRunnerName:
|
||||
r.RunnerName = value
|
||||
return StageInputCustomLabels
|
||||
case StageInputCustomLabels:
|
||||
r.CustomLabels = defaultLabels
|
||||
// if there are some labels configured in config file, skip input labels stage
|
||||
if len(cfg.Runner.Labels) > 0 {
|
||||
ls := make([]string, 0, len(cfg.Runner.Labels))
|
||||
for _, l := range cfg.Runner.Labels {
|
||||
_, err := labels.Parse(l)
|
||||
if err != nil {
|
||||
log.WithError(err).Warnf("ignored invalid label %q", l)
|
||||
continue
|
||||
}
|
||||
ls = append(ls, l)
|
||||
}
|
||||
if len(ls) == 0 {
|
||||
log.Warn("no valid labels configured in config file, runner may not be able to pick up jobs")
|
||||
}
|
||||
r.Labels = ls
|
||||
return StageWaitingForRegistration
|
||||
}
|
||||
return StageInputLabels
|
||||
case StageInputLabels:
|
||||
r.Labels = defaultLabels
|
||||
if value != "" {
|
||||
r.CustomLabels = strings.Split(value, ",")
|
||||
r.Labels = strings.Split(value, ",")
|
||||
}
|
||||
|
||||
if validateLabels(r.CustomLabels) != nil {
|
||||
if validateLabels(r.Labels) != nil {
|
||||
log.Infoln("Invalid labels, please input again, leave blank to use the default labels (for example, ubuntu-20.04:docker://node:16-bullseye,ubuntu-18.04:docker://node:16-buster,linux_arm:host)")
|
||||
return StageInputCustomLabels
|
||||
return StageInputLabels
|
||||
}
|
||||
return StageWaitingForRegistration
|
||||
}
|
||||
@@ -192,12 +209,12 @@ func registerInteractive(configFile string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stage = inputs.assignToNext(stage, strings.TrimSpace(cmdString))
|
||||
stage = inputs.assignToNext(stage, strings.TrimSpace(cmdString), cfg)
|
||||
|
||||
if stage == StageWaitingForRegistration {
|
||||
log.Infof("Registering runner, name=%s, instance=%s, labels=%v.", inputs.RunnerName, inputs.InstanceAddr, inputs.CustomLabels)
|
||||
log.Infof("Registering runner, name=%s, instance=%s, labels=%v.", inputs.RunnerName, inputs.InstanceAddr, inputs.Labels)
|
||||
if err := doRegister(cfg, inputs); err != nil {
|
||||
log.Errorf("Failed to register runner: %v", err)
|
||||
return fmt.Errorf("Failed to register runner: %w", err)
|
||||
} else {
|
||||
log.Infof("Runner registered successfully.")
|
||||
}
|
||||
@@ -226,7 +243,7 @@ func printStageHelp(stage registerStage) {
|
||||
case StageInputRunnerName:
|
||||
hostname, _ := os.Hostname()
|
||||
log.Infof("Enter the runner name (if set empty, use hostname: %s):\n", hostname)
|
||||
case StageInputCustomLabels:
|
||||
case StageInputLabels:
|
||||
log.Infoln("Enter the runner labels, leave blank to use the default labels (comma-separated, for example, ubuntu-20.04:docker://node:16-bullseye,ubuntu-18.04:docker://node:16-buster,linux_arm:host):")
|
||||
case StageWaitingForRegistration:
|
||||
log.Infoln("Waiting for registration...")
|
||||
@@ -242,12 +259,21 @@ func registerNoInteractive(configFile string, regArgs *registerArgs) error {
|
||||
InstanceAddr: regArgs.InstanceAddr,
|
||||
Token: regArgs.Token,
|
||||
RunnerName: regArgs.RunnerName,
|
||||
CustomLabels: defaultLabels,
|
||||
Labels: defaultLabels,
|
||||
}
|
||||
regArgs.Labels = strings.TrimSpace(regArgs.Labels)
|
||||
// command line flag.
|
||||
if regArgs.Labels != "" {
|
||||
inputs.CustomLabels = strings.Split(regArgs.Labels, ",")
|
||||
inputs.Labels = strings.Split(regArgs.Labels, ",")
|
||||
}
|
||||
// specify labels in config file.
|
||||
if len(cfg.Runner.Labels) > 0 {
|
||||
if regArgs.Labels != "" {
|
||||
log.Warn("Labels from command will be ignored, use labels defined in config file.")
|
||||
}
|
||||
inputs.Labels = cfg.Runner.Labels
|
||||
}
|
||||
|
||||
if inputs.RunnerName == "" {
|
||||
inputs.RunnerName, _ = os.Hostname()
|
||||
log.Infof("Runner name is empty, use hostname '%s'.", inputs.RunnerName)
|
||||
@@ -257,8 +283,7 @@ func registerNoInteractive(configFile string, regArgs *registerArgs) error {
|
||||
return nil
|
||||
}
|
||||
if err := doRegister(cfg, inputs); err != nil {
|
||||
log.Errorf("Failed to register runner: %v", err)
|
||||
return nil
|
||||
return fmt.Errorf("Failed to register runner: %w", err)
|
||||
}
|
||||
log.Infof("Runner registered successfully.")
|
||||
return nil
|
||||
@@ -303,7 +328,7 @@ func doRegister(cfg *config.Config, inputs *registerInputs) error {
|
||||
Name: inputs.RunnerName,
|
||||
Token: inputs.Token,
|
||||
Address: inputs.InstanceAddr,
|
||||
Labels: inputs.CustomLabels,
|
||||
Labels: inputs.Labels,
|
||||
}
|
||||
|
||||
ls := make([]string, len(reg.Labels))
|
||||
@@ -315,7 +340,9 @@ func doRegister(cfg *config.Config, inputs *registerInputs) error {
|
||||
resp, err := cli.Register(ctx, connect.NewRequest(&runnerv1.RegisterRequest{
|
||||
Name: reg.Name,
|
||||
Token: reg.Token,
|
||||
AgentLabels: ls,
|
||||
Version: ver.Version(),
|
||||
AgentLabels: ls, // Could be removed after Gitea 1.20
|
||||
Labels: ls,
|
||||
}))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("poller: cannot register new runner")
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"time"
|
||||
|
||||
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
|
||||
"github.com/bufbuild/connect-go"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/nektos/act/pkg/artifactcache"
|
||||
"github.com/nektos/act/pkg/common"
|
||||
@@ -177,26 +178,26 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report.
|
||||
Workdir: filepath.FromSlash(fmt.Sprintf("/%s/%s", r.cfg.Container.WorkdirParent, preset.Repository)),
|
||||
BindWorkdir: false,
|
||||
|
||||
ReuseContainers: false,
|
||||
ForcePull: false,
|
||||
ForceRebuild: false,
|
||||
LogOutput: true,
|
||||
JSONLogger: false,
|
||||
Env: r.envs,
|
||||
Secrets: task.Secrets,
|
||||
GitHubInstance: strings.TrimSuffix(r.client.Address(), "/"),
|
||||
AutoRemove: true,
|
||||
NoSkipCheckout: true,
|
||||
PresetGitHubContext: preset,
|
||||
EventJSON: string(eventJSON),
|
||||
ContainerNamePrefix: fmt.Sprintf("GITEA-ACTIONS-TASK-%d", task.Id),
|
||||
ContainerMaxLifetime: maxLifetime,
|
||||
ContainerNetworkMode: container.NetworkMode(r.cfg.Container.Network),
|
||||
ContainerOptions: r.cfg.Container.Options,
|
||||
Privileged: r.cfg.Container.Privileged,
|
||||
DefaultActionInstance: taskContext["gitea_default_actions_url"].GetStringValue(),
|
||||
PlatformPicker: r.labels.PickPlatform,
|
||||
Vars: task.Vars,
|
||||
ReuseContainers: false,
|
||||
ForcePull: false,
|
||||
ForceRebuild: false,
|
||||
LogOutput: true,
|
||||
JSONLogger: false,
|
||||
Env: r.envs,
|
||||
Secrets: task.Secrets,
|
||||
GitHubInstance: strings.TrimSuffix(r.client.Address(), "/"),
|
||||
AutoRemove: true,
|
||||
NoSkipCheckout: true,
|
||||
PresetGitHubContext: preset,
|
||||
EventJSON: string(eventJSON),
|
||||
ContainerNamePrefix: fmt.Sprintf("GITEA-ACTIONS-TASK-%d", task.Id),
|
||||
ContainerMaxLifetime: maxLifetime,
|
||||
ContainerNetworkMode: container.NetworkMode(r.cfg.Container.Network),
|
||||
ContainerOptions: r.cfg.Container.Options,
|
||||
Privileged: r.cfg.Container.Privileged,
|
||||
DefaultActionsURLs: parseDefaultActionsURLs(taskContext["gitea_default_actions_url"].GetStringValue()),
|
||||
PlatformPicker: r.labels.PickPlatform,
|
||||
Vars: task.Vars,
|
||||
}
|
||||
|
||||
rr, err := runner.New(runnerConfig)
|
||||
@@ -214,3 +215,20 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report.
|
||||
reporter.SetOutputs(job.Outputs)
|
||||
return execErr
|
||||
}
|
||||
|
||||
func parseDefaultActionsURLs(s string) []string {
|
||||
urls := strings.Split(s, ",")
|
||||
trimmed := make([]string, 0, len(urls))
|
||||
for _, u := range urls {
|
||||
t := strings.TrimRight(strings.TrimSpace(u), "/")
|
||||
trimmed = append(trimmed, t)
|
||||
}
|
||||
return trimmed
|
||||
}
|
||||
|
||||
func (r *Runner) Declare(ctx context.Context, labels []string) (*connect.Response[runnerv1.DeclareResponse], error) {
|
||||
return r.client.Declare(ctx, connect.NewRequest(&runnerv1.DeclareRequest{
|
||||
Version: ver.Version(),
|
||||
Labels: labels,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
package client
|
||||
|
||||
const (
|
||||
UUIDHeader = "x-runner-uuid"
|
||||
TokenHeader = "x-runner-token"
|
||||
UUIDHeader = "x-runner-uuid"
|
||||
TokenHeader = "x-runner-token"
|
||||
// Deprecated: could be removed after Gitea 1.20 released
|
||||
VersionHeader = "x-runner-version"
|
||||
)
|
||||
|
||||
@@ -39,6 +39,7 @@ func New(endpoint string, insecure bool, uuid, token, version string, opts ...co
|
||||
if token != "" {
|
||||
req.Header().Set(TokenHeader, token)
|
||||
}
|
||||
// TODO: version will be removed from request header after Gitea 1.20 released.
|
||||
if version != "" {
|
||||
req.Header().Set(VersionHeader, version)
|
||||
}
|
||||
|
||||
@@ -33,6 +33,32 @@ func (_m *Client) Address() string {
|
||||
return r0
|
||||
}
|
||||
|
||||
// Declare provides a mock function with given fields: _a0, _a1
|
||||
func (_m *Client) Declare(_a0 context.Context, _a1 *connect.Request[runnerv1.DeclareRequest]) (*connect.Response[runnerv1.DeclareResponse], error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *connect.Response[runnerv1.DeclareResponse]
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[runnerv1.DeclareRequest]) (*connect.Response[runnerv1.DeclareResponse], error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[runnerv1.DeclareRequest]) *connect.Response[runnerv1.DeclareResponse]); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*connect.Response[runnerv1.DeclareResponse])
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *connect.Request[runnerv1.DeclareRequest]) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// FetchTask provides a mock function with given fields: _a0, _a1
|
||||
func (_m *Client) FetchTask(_a0 context.Context, _a1 *connect.Request[runnerv1.FetchTaskRequest]) (*connect.Response[runnerv1.FetchTaskResponse], error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
@@ -26,6 +26,11 @@ runner:
|
||||
fetch_timeout: 5s
|
||||
# The interval for fetching the job from the Gitea instance.
|
||||
fetch_interval: 2s
|
||||
# The labels of a runner are used to determine which jobs the runner can run, and how to run them.
|
||||
# Like: ["macos-arm64:host", "ubuntu-latest:docker://node:16-bullseye", "ubuntu-22.04:docker://node:16-bullseye"]
|
||||
# If it's empty when registering, it will ask for inputting labels.
|
||||
# If it's empty when execute `deamon`, will use labels in `.runner` file.
|
||||
labels: []
|
||||
|
||||
cache:
|
||||
# Enable cache server to use actions/cache.
|
||||
|
||||
@@ -29,6 +29,7 @@ type Runner struct {
|
||||
Insecure bool `yaml:"insecure"` // Insecure indicates whether the runner operates in an insecure mode.
|
||||
FetchTimeout time.Duration `yaml:"fetch_timeout"` // FetchTimeout specifies the timeout duration for fetching resources.
|
||||
FetchInterval time.Duration `yaml:"fetch_interval"` // FetchInterval specifies the interval duration for fetching resources.
|
||||
Labels []string `yaml:"labels"` // Labels specifies the labels of the runner. Labels are declared on each startup
|
||||
}
|
||||
|
||||
// Cache represents the configuration for caching.
|
||||
@@ -61,14 +62,12 @@ type Config struct {
|
||||
func LoadDefault(file string) (*Config, error) {
|
||||
cfg := &Config{}
|
||||
if file != "" {
|
||||
f, err := os.Open(file)
|
||||
content, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("open config file %q: %w", file, err)
|
||||
}
|
||||
defer f.Close()
|
||||
decoder := yaml.NewDecoder(f)
|
||||
if err := decoder.Decode(&cfg); err != nil {
|
||||
return nil, err
|
||||
if err := yaml.Unmarshal(content, cfg); err != nil {
|
||||
return nil, fmt.Errorf("parse config file %q: %w", file, err)
|
||||
}
|
||||
}
|
||||
compatibleWithOldEnvs(file != "", cfg)
|
||||
|
||||
@@ -82,3 +82,26 @@ func (l Labels) PickPlatform(runsOn []string) string {
|
||||
// TODO: it may be not correct, what if the runner is used as host mode only?
|
||||
return "node:16-bullseye"
|
||||
}
|
||||
|
||||
func (l Labels) Names() []string {
|
||||
names := make([]string, 0, len(l))
|
||||
for _, label := range l {
|
||||
names = append(names, label.Name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
func (l Labels) ToStrings() []string {
|
||||
ls := make([]string, 0, len(l))
|
||||
for _, label := range l {
|
||||
lbl := label.Name
|
||||
if label.Schema != "" {
|
||||
lbl += ":" + label.Schema
|
||||
if label.Arg != "" {
|
||||
lbl += ":" + label.Arg
|
||||
}
|
||||
}
|
||||
ls = append(ls, lbl)
|
||||
}
|
||||
return ls
|
||||
}
|
||||
|
||||
9
scripts/rootless.sh
Executable file
9
scripts/rootless.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# wait for docker daemon
|
||||
while ! nc -z localhost 2376 </dev/null; do
|
||||
echo 'waiting for docker daemon...'
|
||||
sleep 5
|
||||
done
|
||||
|
||||
. /opt/act/run.sh
|
||||
@@ -10,6 +10,10 @@ CONFIG_ARG=""
|
||||
if [[ ! -z "${CONFIG_FILE}" ]]; then
|
||||
CONFIG_ARG="--config ${CONFIG_FILE}"
|
||||
fi
|
||||
EXTRA_ARGS=""
|
||||
if [[ ! -z "${GITEA_RUNNER_LABELS}" ]]; then
|
||||
EXTRA_ARGS="${EXTRA_ARGS} --labels ${GITEA_RUNNER_LABELS}"
|
||||
fi
|
||||
|
||||
# Use the same ENV variable names as https://github.com/vegardit/docker-gitea-act-runner
|
||||
|
||||
@@ -26,10 +30,7 @@ if [[ ! -s .runner ]]; then
|
||||
--instance "${GITEA_INSTANCE_URL}" \
|
||||
--token "${GITEA_RUNNER_REGISTRATION_TOKEN}" \
|
||||
--name "${GITEA_RUNNER_NAME:-`hostname`}" \
|
||||
--labels "${GITEA_RUNNER_LABELS}" \
|
||||
${CONFIG_ARG} --no-interactive > /tmp/reg.log 2>&1
|
||||
|
||||
cat /tmp/reg.log
|
||||
${CONFIG_ARG} ${EXTRA_ARGS} --no-interactive 2>&1 | tee /tmp/reg.log
|
||||
|
||||
cat /tmp/reg.log | grep 'Runner registered successfully' > /dev/null
|
||||
if [[ $? -eq 0 ]]; then
|
||||
13
scripts/supervisord.conf
Normal file
13
scripts/supervisord.conf
Normal file
@@ -0,0 +1,13 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
logfile=/dev/null
|
||||
logfile_maxbytes=0
|
||||
|
||||
[program:dockerd]
|
||||
command=/usr/local/bin/dockerd-entrypoint.sh
|
||||
|
||||
[program:act_runner]
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
redirect_stderr=true
|
||||
command=/opt/act/rootless.sh
|
||||
Reference in New Issue
Block a user