mirror of
https://gitea.com/gitea/act_runner.git
synced 2025-12-18 12:04:47 +00:00
Compare commits
8 Commits
fed01c9807
...
v0.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45bfe0a9b2 | ||
|
|
316534996a | ||
|
|
67b1363d25 | ||
|
|
946c41cf4f | ||
|
|
341d49a24d | ||
|
|
b21d476aca | ||
|
|
a29307a9d9 | ||
|
|
4bfbfec477 |
@@ -58,11 +58,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0 # all history for all branches and tags
|
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
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
@@ -95,3 +90,16 @@ jobs:
|
|||||||
tags: |
|
tags: |
|
||||||
${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}
|
${{ 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:
|
with:
|
||||||
fetch-depth: 0 # all history for all branches and tags
|
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
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
@@ -106,3 +101,18 @@ jobs:
|
|||||||
tags: |
|
tags: |
|
||||||
${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }}
|
${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }}
|
||||||
${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}
|
${{ 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
|
run: make build
|
||||||
- name: test
|
- name: test
|
||||||
run: make 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`
|
# 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
|
COPY . /opt/src/act_runner
|
||||||
WORKDIR /opt/src/act_runner
|
WORKDIR /opt/src/act_runner
|
||||||
|
|
||||||
RUN make clean && make build
|
RUN make clean && make build
|
||||||
|
|
||||||
FROM alpine:3.17
|
FROM alpine:3.18
|
||||||
RUN apk add --no-cache \
|
RUN apk add --no-cache git bash tini
|
||||||
git=2.38.5-r0 bash=5.2.15-r0 tini=0.19.0-r1 \
|
|
||||||
&& rm -rf /var/cache/apk/*
|
|
||||||
|
|
||||||
COPY --from=builder /opt/src/act_runner/act_runner /usr/local/bin/act_runner
|
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"]
|
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_IMAGE ?= gitea/act_runner
|
||||||
DOCKER_TAG ?= nightly
|
DOCKER_TAG ?= nightly
|
||||||
DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)
|
DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)
|
||||||
|
DOCKER_ROOTLESS_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)-dind-rootless
|
||||||
|
|
||||||
ifneq ($(shell uname), Darwin)
|
ifneq ($(shell uname), Darwin)
|
||||||
EXTLDFLAGS = -extldflags "-static" $(null)
|
EXTLDFLAGS = -extldflags "-static" $(null)
|
||||||
@@ -69,7 +70,7 @@ GO_PACKAGES_TO_VET ?= $(filter-out gitea.com/gitea/act_runner/internal/pkg/clien
|
|||||||
|
|
||||||
|
|
||||||
TAGS ?=
|
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
|
all: build
|
||||||
|
|
||||||
@@ -169,6 +170,7 @@ docker:
|
|||||||
ARG_DISABLE_CONTENT_TRUST=--disable-content-trust=false; \
|
ARG_DISABLE_CONTENT_TRUST=--disable-content-trust=false; \
|
||||||
fi; \
|
fi; \
|
||||||
docker build $${ARG_DISABLE_CONTENT_TRUST} -t $(DOCKER_REF) .
|
docker build $${ARG_DISABLE_CONTENT_TRUST} -t $(DOCKER_REF) .
|
||||||
|
docker build $${ARG_DISABLE_CONTENT_TRUST} -t $(DOCKER_ROOTLESS_REF) -f Dockerfile.rootless .
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(GO) clean -x -i ./...
|
$(GO) clean -x -i ./...
|
||||||
|
|||||||
@@ -6,3 +6,6 @@ Files in this directory:
|
|||||||
|
|
||||||
- [`dind-docker.yaml`](dind-docker.yaml)
|
- [`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.
|
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
|
||||||
|
|
||||||
2
go.mod
2
go.mod
@@ -3,7 +3,7 @@ module gitea.com/gitea/act_runner
|
|||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require (
|
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
|
code.gitea.io/gitea-vet v0.2.3-0.20230113022436-2b1561217fa5
|
||||||
github.com/avast/retry-go/v4 v4.3.1
|
github.com/avast/retry-go/v4 v4.3.1
|
||||||
github.com/bufbuild/connect-go v1.3.1
|
github.com/bufbuild/connect-go v1.3.1
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -1,5 +1,5 @@
|
|||||||
code.gitea.io/actions-proto-go v0.2.1 h1:ToMN/8thz2q10TuCq8dL2d8mI+/pWpJcHCvG+TELwa0=
|
code.gitea.io/actions-proto-go v0.3.0 h1:9Tvg8+TaaCXPKi6EnWl9vVgs2VZsj1Cs5afnsHa4AmM=
|
||||||
code.gitea.io/actions-proto-go v0.2.1/go.mod h1:00ys5QDo1iHN1tHNvvddAcy2W/g+425hQya1cCSvq9A=
|
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 h1:daBEK2GQeqGikJESctP5Cu1i33z5ztAD4kyQWiw185M=
|
||||||
code.gitea.io/gitea-vet v0.2.3-0.20230113022436-2b1561217fa5/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
|
code.gitea.io/gitea-vet v0.2.3-0.20230113022436-2b1561217fa5/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
|
||||||
gitea.com/gitea/act v0.245.2-0.20230606002131-6ce5c93cc815 h1:u4rHwJLJnH6mej1BjEc4iubwknVeJmRVq9xQP9cAMeQ=
|
gitea.com/gitea/act v0.245.2-0.20230606002131-6ce5c93cc815 h1:u4rHwJLJnH6mej1BjEc4iubwknVeJmRVq9xQP9cAMeQ=
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/bufbuild/connect-go"
|
||||||
"github.com/mattn/go-isatty"
|
"github.com/mattn/go-isatty"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"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)
|
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{}
|
ls := labels.Labels{}
|
||||||
for _, l := range reg.Labels {
|
for _, l := range lbls {
|
||||||
label, err := labels.Parse(l)
|
label, err := labels.Parse(l)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Warnf("ignored invalid label %q", l)
|
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)
|
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.New(cfg, cli, runner)
|
||||||
|
|
||||||
poller.Poll(ctx)
|
poller.Poll(ctx)
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ type executeArgs struct {
|
|||||||
envs []string
|
envs []string
|
||||||
envfile string
|
envfile string
|
||||||
secrets []string
|
secrets []string
|
||||||
defaultActionsUrl string
|
defaultActionsUrls []string
|
||||||
insecureSecrets bool
|
insecureSecrets bool
|
||||||
privileged bool
|
privileged bool
|
||||||
usernsMode string
|
usernsMode string
|
||||||
@@ -403,10 +403,10 @@ func runExec(ctx context.Context, execArgs *executeArgs) func(cmd *cobra.Command
|
|||||||
NoSkipCheckout: execArgs.noSkipCheckout,
|
NoSkipCheckout: execArgs.noSkipCheckout,
|
||||||
// PresetGitHubContext: preset,
|
// PresetGitHubContext: preset,
|
||||||
// EventJSON: string(eventJSON),
|
// EventJSON: string(eventJSON),
|
||||||
ContainerNamePrefix: fmt.Sprintf("GITEA-ACTIONS-TASK-%s", eventName),
|
ContainerNamePrefix: fmt.Sprintf("GITEA-ACTIONS-TASK-%s", eventName),
|
||||||
ContainerMaxLifetime: maxLifetime,
|
ContainerMaxLifetime: maxLifetime,
|
||||||
ContainerNetworkMode: container.NetworkMode(execArgs.network),
|
ContainerNetworkMode: container.NetworkMode(execArgs.network),
|
||||||
DefaultActionInstance: execArgs.defaultActionsUrl,
|
DefaultActionsURLs: execArgs.defaultActionsUrls,
|
||||||
PlatformPicker: func(_ []string) string {
|
PlatformPicker: func(_ []string) string {
|
||||||
return execArgs.image
|
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.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.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.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.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.debug, "debug", "d", false, "enable debug log")
|
||||||
execCmd.PersistentFlags().BoolVarP(&execArg.dryrun, "dryrun", "n", false, "dryrun mode")
|
execCmd.PersistentFlags().BoolVarP(&execArg.dryrun, "dryrun", "n", false, "dryrun mode")
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ const (
|
|||||||
StageInputInstance
|
StageInputInstance
|
||||||
StageInputToken
|
StageInputToken
|
||||||
StageInputRunnerName
|
StageInputRunnerName
|
||||||
StageInputCustomLabels
|
StageInputLabels
|
||||||
StageWaitingForRegistration
|
StageWaitingForRegistration
|
||||||
StageExit
|
StageExit
|
||||||
)
|
)
|
||||||
@@ -101,7 +101,7 @@ type registerInputs struct {
|
|||||||
InstanceAddr string
|
InstanceAddr string
|
||||||
Token string
|
Token string
|
||||||
RunnerName string
|
RunnerName string
|
||||||
CustomLabels []string
|
Labels []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *registerInputs) validate() error {
|
func (r *registerInputs) validate() error {
|
||||||
@@ -111,8 +111,8 @@ func (r *registerInputs) validate() error {
|
|||||||
if r.Token == "" {
|
if r.Token == "" {
|
||||||
return fmt.Errorf("token is empty")
|
return fmt.Errorf("token is empty")
|
||||||
}
|
}
|
||||||
if len(r.CustomLabels) > 0 {
|
if len(r.Labels) > 0 {
|
||||||
return validateLabels(r.CustomLabels)
|
return validateLabels(r.Labels)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -126,7 +126,7 @@ func validateLabels(ls []string) error {
|
|||||||
return nil
|
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.
|
// must set instance address and token.
|
||||||
// if empty, keep current stage.
|
// if empty, keep current stage.
|
||||||
if stage == StageInputInstance || stage == StageInputToken {
|
if stage == StageInputInstance || stage == StageInputToken {
|
||||||
@@ -154,16 +154,33 @@ func (r *registerInputs) assignToNext(stage registerStage, value string) registe
|
|||||||
return StageInputRunnerName
|
return StageInputRunnerName
|
||||||
case StageInputRunnerName:
|
case StageInputRunnerName:
|
||||||
r.RunnerName = value
|
r.RunnerName = value
|
||||||
return StageInputCustomLabels
|
// if there are some labels configured in config file, skip input labels stage
|
||||||
case StageInputCustomLabels:
|
if len(cfg.Runner.Labels) > 0 {
|
||||||
r.CustomLabels = defaultLabels
|
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 != "" {
|
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)")
|
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
|
return StageWaitingForRegistration
|
||||||
}
|
}
|
||||||
@@ -192,12 +209,12 @@ func registerInteractive(configFile string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
stage = inputs.assignToNext(stage, strings.TrimSpace(cmdString))
|
stage = inputs.assignToNext(stage, strings.TrimSpace(cmdString), cfg)
|
||||||
|
|
||||||
if stage == StageWaitingForRegistration {
|
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 {
|
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 {
|
} else {
|
||||||
log.Infof("Runner registered successfully.")
|
log.Infof("Runner registered successfully.")
|
||||||
}
|
}
|
||||||
@@ -226,7 +243,7 @@ func printStageHelp(stage registerStage) {
|
|||||||
case StageInputRunnerName:
|
case StageInputRunnerName:
|
||||||
hostname, _ := os.Hostname()
|
hostname, _ := os.Hostname()
|
||||||
log.Infof("Enter the runner name (if set empty, use hostname: %s):\n", 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):")
|
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:
|
case StageWaitingForRegistration:
|
||||||
log.Infoln("Waiting for registration...")
|
log.Infoln("Waiting for registration...")
|
||||||
@@ -242,12 +259,21 @@ func registerNoInteractive(configFile string, regArgs *registerArgs) error {
|
|||||||
InstanceAddr: regArgs.InstanceAddr,
|
InstanceAddr: regArgs.InstanceAddr,
|
||||||
Token: regArgs.Token,
|
Token: regArgs.Token,
|
||||||
RunnerName: regArgs.RunnerName,
|
RunnerName: regArgs.RunnerName,
|
||||||
CustomLabels: defaultLabels,
|
Labels: defaultLabels,
|
||||||
}
|
}
|
||||||
regArgs.Labels = strings.TrimSpace(regArgs.Labels)
|
regArgs.Labels = strings.TrimSpace(regArgs.Labels)
|
||||||
|
// command line flag.
|
||||||
if regArgs.Labels != "" {
|
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 == "" {
|
if inputs.RunnerName == "" {
|
||||||
inputs.RunnerName, _ = os.Hostname()
|
inputs.RunnerName, _ = os.Hostname()
|
||||||
log.Infof("Runner name is empty, use hostname '%s'.", inputs.RunnerName)
|
log.Infof("Runner name is empty, use hostname '%s'.", inputs.RunnerName)
|
||||||
@@ -257,8 +283,7 @@ func registerNoInteractive(configFile string, regArgs *registerArgs) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err := doRegister(cfg, inputs); err != nil {
|
if err := doRegister(cfg, inputs); err != nil {
|
||||||
log.Errorf("Failed to register runner: %v", err)
|
return fmt.Errorf("Failed to register runner: %w", err)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
log.Infof("Runner registered successfully.")
|
log.Infof("Runner registered successfully.")
|
||||||
return nil
|
return nil
|
||||||
@@ -303,7 +328,7 @@ func doRegister(cfg *config.Config, inputs *registerInputs) error {
|
|||||||
Name: inputs.RunnerName,
|
Name: inputs.RunnerName,
|
||||||
Token: inputs.Token,
|
Token: inputs.Token,
|
||||||
Address: inputs.InstanceAddr,
|
Address: inputs.InstanceAddr,
|
||||||
Labels: inputs.CustomLabels,
|
Labels: inputs.Labels,
|
||||||
}
|
}
|
||||||
|
|
||||||
ls := make([]string, len(reg.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{
|
resp, err := cli.Register(ctx, connect.NewRequest(&runnerv1.RegisterRequest{
|
||||||
Name: reg.Name,
|
Name: reg.Name,
|
||||||
Token: reg.Token,
|
Token: reg.Token,
|
||||||
AgentLabels: ls,
|
Version: ver.Version(),
|
||||||
|
AgentLabels: ls, // Could be removed after Gitea 1.20
|
||||||
|
Labels: ls,
|
||||||
}))
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("poller: cannot register new runner")
|
log.WithError(err).Error("poller: cannot register new runner")
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
|
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
|
||||||
|
"github.com/bufbuild/connect-go"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/nektos/act/pkg/artifactcache"
|
"github.com/nektos/act/pkg/artifactcache"
|
||||||
"github.com/nektos/act/pkg/common"
|
"github.com/nektos/act/pkg/common"
|
||||||
@@ -224,3 +225,10 @@ func parseDefaultActionsURLs(s string) []string {
|
|||||||
}
|
}
|
||||||
return trimmed
|
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
|
package client
|
||||||
|
|
||||||
const (
|
const (
|
||||||
UUIDHeader = "x-runner-uuid"
|
UUIDHeader = "x-runner-uuid"
|
||||||
TokenHeader = "x-runner-token"
|
TokenHeader = "x-runner-token"
|
||||||
|
// Deprecated: could be removed after Gitea 1.20 released
|
||||||
VersionHeader = "x-runner-version"
|
VersionHeader = "x-runner-version"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ func New(endpoint string, insecure bool, uuid, token, version string, opts ...co
|
|||||||
if token != "" {
|
if token != "" {
|
||||||
req.Header().Set(TokenHeader, token)
|
req.Header().Set(TokenHeader, token)
|
||||||
}
|
}
|
||||||
|
// TODO: version will be removed from request header after Gitea 1.20 released.
|
||||||
if version != "" {
|
if version != "" {
|
||||||
req.Header().Set(VersionHeader, version)
|
req.Header().Set(VersionHeader, version)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,32 @@ func (_m *Client) Address() string {
|
|||||||
return r0
|
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
|
// 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) {
|
func (_m *Client) FetchTask(_a0 context.Context, _a1 *connect.Request[runnerv1.FetchTaskRequest]) (*connect.Response[runnerv1.FetchTaskResponse], error) {
|
||||||
ret := _m.Called(_a0, _a1)
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ runner:
|
|||||||
fetch_timeout: 5s
|
fetch_timeout: 5s
|
||||||
# The interval for fetching the job from the Gitea instance.
|
# The interval for fetching the job from the Gitea instance.
|
||||||
fetch_interval: 2s
|
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:
|
cache:
|
||||||
# Enable cache server to use actions/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.
|
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.
|
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.
|
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.
|
// Cache represents the configuration for caching.
|
||||||
@@ -61,14 +62,12 @@ type Config struct {
|
|||||||
func LoadDefault(file string) (*Config, error) {
|
func LoadDefault(file string) (*Config, error) {
|
||||||
cfg := &Config{}
|
cfg := &Config{}
|
||||||
if file != "" {
|
if file != "" {
|
||||||
f, err := os.Open(file)
|
content, err := os.ReadFile(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("open config file %q: %w", file, err)
|
||||||
}
|
}
|
||||||
defer f.Close()
|
if err := yaml.Unmarshal(content, cfg); err != nil {
|
||||||
decoder := yaml.NewDecoder(f)
|
return nil, fmt.Errorf("parse config file %q: %w", file, err)
|
||||||
if err := decoder.Decode(&cfg); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compatibleWithOldEnvs(file != "", cfg)
|
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?
|
// TODO: it may be not correct, what if the runner is used as host mode only?
|
||||||
return "node:16-bullseye"
|
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
|
if [[ ! -z "${CONFIG_FILE}" ]]; then
|
||||||
CONFIG_ARG="--config ${CONFIG_FILE}"
|
CONFIG_ARG="--config ${CONFIG_FILE}"
|
||||||
fi
|
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
|
# 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}" \
|
--instance "${GITEA_INSTANCE_URL}" \
|
||||||
--token "${GITEA_RUNNER_REGISTRATION_TOKEN}" \
|
--token "${GITEA_RUNNER_REGISTRATION_TOKEN}" \
|
||||||
--name "${GITEA_RUNNER_NAME:-`hostname`}" \
|
--name "${GITEA_RUNNER_NAME:-`hostname`}" \
|
||||||
--labels "${GITEA_RUNNER_LABELS}" \
|
${CONFIG_ARG} ${EXTRA_ARGS} --no-interactive 2>&1 | tee /tmp/reg.log
|
||||||
${CONFIG_ARG} --no-interactive > /tmp/reg.log 2>&1
|
|
||||||
|
|
||||||
cat /tmp/reg.log
|
|
||||||
|
|
||||||
cat /tmp/reg.log | grep 'Runner registered successfully' > /dev/null
|
cat /tmp/reg.log | grep 'Runner registered successfully' > /dev/null
|
||||||
if [[ $? -eq 0 ]]; then
|
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