Browse Source

docker: add next-generation rootless image with Kubernetes security context support (#8061)

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: unknwon <[email protected]>
Co-authored-by: Joe Chen <[email protected]>
Copilot 5 days ago
parent
commit
332c0895e6
5 changed files with 362 additions and 12 deletions
  1. 185 8
      .github/workflows/docker.yml
  2. 1 0
      CHANGELOG.md
  3. 48 0
      Dockerfile.next
  4. 119 0
      docker-next/README.md
  5. 9 4
      docker/README.md

+ 185 - 8
.github/workflows/docker.yml

@@ -7,7 +7,9 @@ on:
     paths:
       - '.trivy.yaml'
       - 'Dockerfile'
+      - 'Dockerfile.next'
       - 'docker/**'
+      - 'docker-next/**'
       - '.github/workflows/docker.yml'
   release:
     types: [ published ]
@@ -19,6 +21,75 @@ jobs:
       group: ${{ github.workflow }}-${{ github.ref }}
       cancel-in-progress: true
     runs-on: ubuntu-latest
+    permissions:
+      actions: write
+      contents: read
+      packages: write
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+      - name: Set up QEMU
+        uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
+        with:
+          platforms: linux/amd64,linux/arm64,linux/arm/v7
+      - name: Set up Docker Buildx
+        id: buildx
+        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+      - name: Inspect builder
+        run: |
+          echo "Name:      ${{ steps.buildx.outputs.name }}"
+          echo "Endpoint:  ${{ steps.buildx.outputs.endpoint }}"
+          echo "Status:    ${{ steps.buildx.outputs.status }}"
+          echo "Flags:     ${{ steps.buildx.outputs.flags }}"
+          echo "Platforms: ${{ steps.buildx.outputs.platforms }}"
+      - name: Login to Docker Hub
+        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+        with:
+          username: ${{ secrets.DOCKERHUB_USERNAME }}
+          password: ${{ secrets.DOCKERHUB_TOKEN }}
+      - name: Login to GitHub Container registry
+        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+        with:
+          registry: ghcr.io
+          username: ${{ github.repository_owner }}
+          password: ${{ secrets.GITHUB_TOKEN }}
+      - name: Build and push images
+        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
+        with:
+          context: .
+          platforms: linux/amd64,linux/arm64,linux/arm/v7
+          push: true
+          tags: |
+            gogs/gogs:latest
+            ghcr.io/gogs/gogs:latest
+      - name: Scan for container vulnerabilities
+        uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
+        with:
+          image-ref: gogs/gogs:latest
+          exit-code: '1'
+      - name: Send email on failure
+        uses: dawidd6/action-send-mail@2cea9617b09d79a095af21254fbcb7ae95903dde # v3.12.0
+        if: ${{ failure() }}
+        with:
+          server_address: smtp.mailgun.org
+          server_port: 465
+          username: ${{ secrets.SMTP_USERNAME }}
+          password: ${{ secrets.SMTP_PASSWORD }}
+          subject: GitHub Actions (${{ github.repository }}) job result
+          to: [email protected]
+          from: GitHub Actions (${{ github.repository }})
+          reply_to: [email protected]
+          body: |
+            The job "${{ github.job }}" of ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }} completed with "${{ job.status }}".
+
+            View the job run at: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
+
+  buildx-next:
+    if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository == 'gogs/gogs' }}
+    concurrency:
+      group: ${{ github.workflow }}-next-${{ github.ref }}
+      cancel-in-progress: true
+    runs-on: ubuntu-latest
     permissions:
       actions: write
       contents: read
@@ -57,20 +128,21 @@ jobs:
           registry: registry.digitalocean.com
           username: ${{ secrets.DIGITALOCEAN_USERNAME }}
           password: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
-      - name: Build and push images
+      - name: Build and push next-gen images
         uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
         with:
           context: .
+          file: Dockerfile.next
           platforms: linux/amd64,linux/arm64,linux/arm/v7
           push: true
           tags: |
-            gogs/gogs:latest
-            ghcr.io/gogs/gogs:latest
-            registry.digitalocean.com/gogs/gogs:latest
+            gogs/gogs:next-latest
+            ghcr.io/gogs/gogs:next-latest
+            registry.digitalocean.com/gogs/gogs:next-latest
       - name: Scan for container vulnerabilities
         uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
         with:
-          image-ref: gogs/gogs:latest
+          image-ref: gogs/gogs:next-latest
           exit-code: '1'
       - name: Send email on failure
         uses: dawidd6/action-send-mail@2cea9617b09d79a095af21254fbcb7ae95903dde # v3.12.0
@@ -91,7 +163,7 @@ jobs:
 
   deploy-demo:
     if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository == 'gogs/gogs' }}
-    needs: buildx
+    needs: buildx-next
     runs-on: ubuntu-latest
     permissions:
       contents: read
@@ -157,11 +229,51 @@ jobs:
           platforms: linux/amd64
           push: true
           tags: |
-            ttl.sh/gogs/gogs-${{ steps.short-sha.outputs.sha }}:1d
+            ttl.sh/gogs/gogs-${{ steps.short-sha.outputs.sha }}:7d
+      - name: Scan for container vulnerabilities
+        uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
+        with:
+          image-ref: ttl.sh/gogs/gogs-${{ steps.short-sha.outputs.sha }}:7d
+          exit-code: '1'
+
+  buildx-next-pull-request:
+    if: ${{ github.event_name == 'pull_request'}}
+    runs-on: ubuntu-latest
+    permissions:
+      contents: read
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+      - name: Set up Docker Buildx
+        id: buildx
+        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+        with:
+          config-inline: |
+            [worker.oci]
+              max-parallelism = 2
+      - name: Inspect builder
+        run: |
+          echo "Name:      ${{ steps.buildx.outputs.name }}"
+          echo "Endpoint:  ${{ steps.buildx.outputs.endpoint }}"
+          echo "Status:    ${{ steps.buildx.outputs.status }}"
+          echo "Flags:     ${{ steps.buildx.outputs.flags }}"
+          echo "Platforms: ${{ steps.buildx.outputs.platforms }}"
+      - name: Compute short commit SHA
+        id: short-sha
+        uses: benjlevesque/short-sha@599815c8ee942a9616c92bcfb4f947a3b670ab0b # v3.0
+      - name: Build and push next-gen images
+        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
+        with:
+          context: .
+          file: Dockerfile.next
+          platforms: linux/amd64
+          push: true
+          tags: |
+            ttl.sh/gogs/gogs-next-${{ steps.short-sha.outputs.sha }}:7d
       - name: Scan for container vulnerabilities
         uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
         with:
-          image-ref: ttl.sh/gogs/gogs-${{ steps.short-sha.outputs.sha }}:1d
+          image-ref: ttl.sh/gogs/gogs-next-${{ steps.short-sha.outputs.sha }}:7d
           exit-code: '1'
 
   # Updates to the following section needs to be synced to all release branches within their lifecycles.
@@ -227,3 +339,68 @@ jobs:
             The job "${{ github.job }}" of ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }} completed with "${{ job.status }}".
 
             View the job run at: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
+
+  # Updates to the following section needs to be synced to all release branches within their lifecycles.
+  buildx-next-release:
+    if: ${{ github.event_name == 'release' }}
+    runs-on: ubuntu-latest
+    permissions:
+      actions: write
+      contents: read
+      packages: write
+    steps:
+      - name: Compute image tag name
+        run: echo "IMAGE_TAG=$(echo $GITHUB_REF_NAME | cut -c 2-)" >> $GITHUB_ENV
+      - name: Checkout code
+        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+      - name: Set up QEMU
+        uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
+        with:
+          platforms: linux/amd64,linux/arm64,linux/arm/v7
+      - name: Set up Docker Buildx
+        id: buildx
+        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+      - name: Inspect builder
+        run: |
+          echo "Name:      ${{ steps.buildx.outputs.name }}"
+          echo "Endpoint:  ${{ steps.buildx.outputs.endpoint }}"
+          echo "Status:    ${{ steps.buildx.outputs.status }}"
+          echo "Flags:     ${{ steps.buildx.outputs.flags }}"
+          echo "Platforms: ${{ steps.buildx.outputs.platforms }}"
+      - name: Login to Docker Hub
+        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+        with:
+          username: ${{ secrets.DOCKERHUB_USERNAME }}
+          password: ${{ secrets.DOCKERHUB_TOKEN }}
+      - name: Login to GitHub Container registry
+        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+        with:
+          registry: ghcr.io
+          username: ${{ github.repository_owner }}
+          password: ${{ secrets.GITHUB_TOKEN }}
+      - name: Build and push next-gen images
+        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
+        with:
+          context: .
+          file: Dockerfile.next
+          platforms: linux/amd64,linux/arm64,linux/arm/v7
+          push: true
+          tags: |
+            gogs/gogs:next-${{ env.IMAGE_TAG }}
+            ghcr.io/gogs/gogs:next-${{ env.IMAGE_TAG }}
+      - name: Send email on failure
+        uses: dawidd6/action-send-mail@2cea9617b09d79a095af21254fbcb7ae95903dde # v3.12.0
+        if: ${{ failure() }}
+        with:
+          server_address: smtp.mailgun.org
+          server_port: 465
+          username: ${{ secrets.SMTP_USERNAME }}
+          password: ${{ secrets.SMTP_PASSWORD }}
+          subject: GitHub Actions (${{ github.repository }}) job result
+          to: [email protected]
+          from: GitHub Actions (${{ github.repository }})
+          reply_to: [email protected]
+          body: |
+            The job "${{ github.job }}" of ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }} completed with "${{ job.status }}".
+
+            View the job run at: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}

+ 1 - 0
CHANGELOG.md

@@ -8,6 +8,7 @@ All notable changes to Gogs are documented in this file.
 
 - Support using TLS for Redis session provider using `[session] PROVIDER_CONFIG = ...,tls=true`. [#7860](https://github.com/gogs/gogs/pull/7860)
 - Support expanading values in `app.ini` from environment variables, e.g. `[database] PASSWORD = ${DATABASE_PASSWORD}`. [#8057](https://github.com/gogs/gogs/pull/8057)
+- Start publishing next-generation, security-focused Docker image via `gogs/gogs:next-latest`, which will become the default image distribution (`gogs/gogs:latest`) starting 0.15.0. While not all container options support have been added in the next-generation image, the use of current legacy Docker image is deprecated, it will be published as `gogs/gogs:legacy-latest` starting 0.15.0, and be completely removed starting 0.16.0. [#8061](https://github.com/gogs/gogs/pull/8061)
 
 ### Changed
 

+ 48 - 0
Dockerfile.next

@@ -0,0 +1,48 @@
+FROM golang:alpine3.22 AS binarybuilder
+RUN apk --no-cache --no-progress add --virtual \
+  build-deps \
+  build-base \
+  git \
+  linux-pam-dev
+
+WORKDIR /gogs.io/gogs
+COPY . .
+
+RUN ./docker/build/install-task.sh
+RUN TAGS="cert pam" task build
+
+FROM alpine:3.22
+
+# Create git user and group with fixed UID/GID at build time for better K8s security context support.
+# Using 1000:1000 as it's a common non-root UID/GID that works well with most volume permission setups.
+ARG GOGS_UID=1000
+ARG GOGS_GID=1000
+RUN addgroup -g ${GOGS_GID} -S git && \
+    adduser -u ${GOGS_UID} -G git -H -D -g 'Gogs Git User' -h /data/git -s /bin/sh git
+
+RUN apk --no-cache --no-progress add \
+  bash \
+  ca-certificates \
+  git \
+  linux-pam \
+  openssh-keygen
+
+ENV GOGS_CUSTOM=/data/gogs
+
+WORKDIR /app/gogs
+COPY --from=binarybuilder /gogs.io/gogs/gogs .
+
+# Create data directories and set ownership
+RUN mkdir -p /data/gogs /data/git /backup && \
+    chown -R git:git /app/gogs /data /backup
+
+# Configure Docker Container
+VOLUME ["/data", "/backup"]
+EXPOSE 22 3000
+HEALTHCHECK CMD (curl -o /dev/null -sS http://localhost:3000/healthcheck) || exit 1
+
+# Run as non-root user by default for better K8s security context support.
+USER git:git
+
+ENTRYPOINT ["/app/gogs/gogs"]
+CMD ["web"]

+ 119 - 0
docker-next/README.md

@@ -0,0 +1,119 @@
+# Docker for Gogs (Next Generation)
+
+> [!NOTE]
+> This is the next-generation, security-focused Docker image. This will become the default image distribution (`gogs/gogs:latest`) starting 0.15.0.
+
+![Docker pulls](https://img.shields.io/docker/pulls/gogs/gogs?logo=docker&style=for-the-badge)
+
+Visit [Docker Hub](https://hub.docker.com/u/gogs) or [GitHub Container registry](https://github.com/gogs/gogs/pkgs/container/gogs) to see all available images and tags.
+
+## Security-first design
+
+This Docker image is designed with Kubernetes security best practices in mind:
+
+- **Runs as non-root by default** - uses UID 1000 and GID 1000
+- **Minimal image** - only have essential packages installed
+- **Direct execution** - no process supervisor, just runs `gogs web`
+- **Supports restrictive security contexts** - ready for Kubernetes
+
+### Kubernetes Security Context example
+
+```yaml
+securityContext:
+  runAsNonRoot: true
+  runAsUser: 1000
+  runAsGroup: 1000
+  allowPrivilegeEscalation: false
+  seccompProfile:
+    type: RuntimeDefault
+  capabilities:
+    drop:
+      - ALL
+```
+
+### Custom UID/GID at build time
+
+If you need a different UID/GID, build the image with custom arguments:
+
+```zsh
+docker build -f Dockerfile.next --build-arg GOGS_UID=1001 --build-arg GOGS_GID=1001 -t my-gogs .
+```
+
+## Usage
+
+```zsh
+$ docker pull gogs/gogs:next-latest
+
+# Create local directory for volume.
+$ mkdir -p /var/gogs
+$ chown 1000:1000 /var/gogs
+
+# Use `docker run` for the first time.
+$ docker run --name=gogs -p 10022:22 -p 10880:3000 -v /var/gogs:/data gogs/gogs:next-latest
+
+# Use `docker start` if you have stopped it.
+$ docker start gogs
+```
+
+Files will be stored in local path `/var/gogs`.
+
+Directory `/var/gogs` keeps Git repositories and Gogs data:
+
+```zsh
+/var/gogs
+|-- git
+    |-- gogs-repositories
+|-- gogs
+    |-- conf
+    |-- data
+    |-- log
+|-- ssh
+```
+
+### Using Docker volumes
+
+```zsh
+$ docker volume create --name gogs-data
+$ docker run --name=gogs -p 10022:22 -p 10880:3000 -v gogs-data:/data gogs/gogs:next-latest
+```
+
+## Settings
+
+### Application
+
+Most of the settings are obvious and easy to understand, but there are some settings can be confusing by running Gogs inside Docker:
+
+- **Repository Root Path**: keep it as default value `/home/git/gogs-repositories`
+- **Run User**: default `git` (UID 1000)
+- **Domain**: fill in with Docker container IP (e.g. `192.168.99.100`). But if you want to access your Gogs instance from a different physical machine, please fill in with the hostname or IP address of the Docker host machine.
+- **SSH Port**: Use the exposed port from Docker container. For example, your SSH server listens on `22` inside Docker, **but** you expose it by `10022:22`, then use `10022` for this value.
+- **HTTP Port**: Use port you want Gogs to listen on inside Docker container. For example, your Gogs listens on `3000` inside Docker, **and** you expose it by `10880:3000`, but you still use `3000` for this value.
+- **Application URL**: Use combination of **Domain** and **exposed HTTP Port** values (e.g. `http://192.168.99.100:10880/`).
+
+Full documentation of application settings can be found in the [default `app.ini`](https://github.com/gogs/gogs/blob/main/conf/app.ini).
+
+### Git over SSH
+
+>[!IMPORTANT]
+> Enable and disable of the builtin SSH server requires restart of the container to take effect.
+
+To enable Git over SSH access, the use of builtin SSH server is required as follows in your `app.ini`:
+
+```ini
+[server]
+START_SSH_SERVER = true
+SSH_PORT         = 10022 # The port shown in the clone URL
+SSH_LISTEN_PORT  = 22    # The port that builtin server listens on
+```
+
+## Upgrade
+
+> [!CAUTION]
+> Make sure you have volumed data to somewhere outside Docker container!
+
+Steps to upgrade Gogs with Docker:
+
+- `docker pull gogs/gogs:next-latest`
+- `docker stop gogs`
+- `docker rm gogs`
+- Create a container for the first time and don't forget to do the same for the volume and port mapping.

+ 9 - 4
docker/README.md

@@ -1,5 +1,10 @@
 # Docker for Gogs
 
+> [!WARNING]
+> This is now the legacy Docker image that lacks modern security best practices. It will be published as `gogs/gogs:legacy-latest` starting 0.15.0, and be completely removed starting 0.16.0.
+>
+> To use the next-generation, security-focused Docker image, see [docker-next/README.md](../docker-next/README.md).
+
 ![Docker pulls](https://img.shields.io/docker/pulls/gogs/gogs?logo=docker&style=for-the-badge)
 
 Visit [Docker Hub](https://hub.docker.com/u/gogs) or [GitHub Container registry](https://github.com/gogs/gogs/pkgs/container/gogs) to see all available images and tags.
@@ -9,7 +14,6 @@ Visit [Docker Hub](https://hub.docker.com/u/gogs) or [GitHub Container registry]
 To keep your data out of Docker container, we do a volume (`/var/gogs` -> `/data`) here, and you can change it based on your situation.
 
 ```sh
-# Pull image from Docker Hub.
 $ docker pull gogs/gogs
 
 # Create local directory for volume.
@@ -22,7 +26,7 @@ $ docker run --name=gogs -p 10022:22 -p 10880:3000 -v /var/gogs:/data gogs/gogs
 $ docker start gogs
 ```
 
-Note: It is important to map the SSH service from the container to the host and set the appropriate SSH Port and URI settings when setting up Gogs for the first time. To access and clone Git repositories with the above configuration you would use: `git clone ssh://git@hostname:10022/username/myrepo.git` for example.
+> [!NOTE] It is important to map the SSH service from the container to the host and set the appropriate SSH Port and URI settings when setting up Gogs for the first time. To access and clone Git repositories with the above configuration you would use: `git clone ssh://git@hostname:10022/username/myrepo.git` for example.
 
 Files will be store in local path `/var/gogs` in my case.
 
@@ -138,14 +142,15 @@ Automated backups with retention policy:
 
 ## Upgrade
 
-:exclamation::exclamation::exclamation:<span style="color: red">**Make sure you have volumed data to somewhere outside Docker container**</span>:exclamation::exclamation::exclamation:
+> [!CAUTION]
+> Make sure you have volumed data to somewhere outside Docker container!
 
 Steps to upgrade Gogs with Docker:
 
 - `docker pull gogs/gogs`
 - `docker stop gogs`
 - `docker rm gogs`
-- Finally, create a container for the first time and don't forget to do the same for the volume and port mapping.
+- Create a container for the first time and don't forget to do the same for the volume and port mapping.
 
 ## Known issues