Search code examples
dockergithub-actionsquarkusgiteaquarkus-native

How to build and push quarkus native container in CI?


I just want to build a CI workflow that creates and pushes a quarkus native micro container.

For months, on and off, I've tried to get this to work. I always run into the issue that docker commands won't work in the job.

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

I tried so many ways. Building CI steps one command at a time. Debugging like that. Using other images for the job. Using different actions. It just won't build that Docker image.

It neither worked on gitlab.com nor github.com. So I set up my own Gitea instance, since at some point I read that dind is not supported in those sites. AFAIK, I followed every how-to I could find, on how to set-up action runners to work with dind. But they obviously just don't.

I'm out of ideas. Don't know what to search for anymore. I don't even know what I need to tell you, so you could help me. But I'll try.

I'm running Gitea in a k8s cluster with the official Gitea Helm Chart.

I have a single act_runner deployment. Running fine and doing jobs as it should:

apiVersion: apps/v1
kind: Deployment
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: act-runner
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    spec:
      containers:
        - 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:3000
            - name: GITEA_RUNNER_REGISTRATION_TOKEN
              valueFrom:
                secretKeyRef:
                  key: token
                  name: runner-secret
          image: gitea/act_runner:latest
          imagePullPolicy: Always
          name: runner
          resources: {}
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          volumeMounts:
            - mountPath: /certs
              name: docker-certs
            - mountPath: /data
              name: runner-data
            
        - env:
            - name: DOCKER_TLS_CERTDIR
              value: /certs
          image: docker:23.0.6-dind
          imagePullPolicy: IfNotPresent
          name: daemon
          resources: {}
          securityContext:
            privileged: true
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          volumeMounts:
            - mountPath: /certs
              name: docker-certs
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
      volumes:
        - emptyDir: {}
          name: docker-certs
        - name: runner-data
          persistentVolumeClaim:
            claimName: act-runner-vol

My workflow definition looks like this:

name: Main Push
on:
  push:
    branches:
      - main

jobs:
  verify:
    name: Verify
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up GraalVM JDK
        uses: graalvm/setup-graalvm@v1
        with:
          java-version: '21'
          distribution: 'graalvm'

      - name: Set up Maven
        uses: stCarolas/setup-maven@v4
        with:
          maven-version: '3.9.6'

      - name: Maven Verify
        run: mvn --batch-mode --update-snapshots verify

  push_container:
    needs: verify
    name: Push Container
    runs-on: ubuntu-latest
    container:
      image: catthehacker/ubuntu:act-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up GraalVM JDK
        uses: graalvm/setup-graalvm@v1
        with:
          java-version: '21'
          distribution: 'graalvm'

      - name: Set up Maven
        uses: stCarolas/setup-maven@v4
        with:
          maven-version: '3.9.6'

      - name: Maven Install
        run: mvn --batch-mode --update-snapshots install -Dnative -Dquarkus.container-image.build=true -Dquarkus.container-image.push=true -Dquarkus.container-image.username=dscham -Dquarkus.container-image.password=${{ secrets.GITEA_TOKEN }}

Everything runs through. Only in the end, when the maven install command get's to building the container image, it fails due to aforementioned error. I used different images for the job. Tried installing docker in a manual step. Used a setup docker action from Action Marketplace. Nothing worked to fix this.

Edit/Addition:

Trying both methods described by @datawookie in his answer, I get:

Client:
 Version:           24.0.9-2
 API version:       1.43
 Go version:        go1.21.9
 Git commit:        293681613032e6d1a39cc88115847d3984195c24
 Built:             Wed Jan 31 20:53:14 UTC 2024
 OS/Arch:           linux/amd64
 Context:           default
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

Solution

  • So, I couldn't get docker commands to work on GitLab.com CI/CD. And what I found was, that this just doesn't work there, because of insufficient permissions in the runners.

    Therefore, I self-hosted Gitea in k8s and deployed my own runner there too. Still didn't work.

    Why? As I found out with people on Gitea Discord, k8s doesn't like mounting sockets from the runner into the job container. And I wasn't able to find anything online on it, because very most people just run everything Gitea in Docker, not k8s.

    But, in the end, I found a workaround. The gitea/act_runner, can be configured with a config.yaml. And there you can set container.privileged: true. So I deployed a ConfigMap, mounted it into the act_runner deployment as the config.yaml and et voila, I can run docker in the job containers.

    This only works when act_runner is running as root. But this way, I was able to install Docker in the job and FINALLY, Maven was able to run the docker container for the quarkus native build and in the end build and push the final result container to the Gitea registry.