Skip to content

DOCKERization!#99

Open
Fragoler wants to merge 7 commits intospace-exodus:mainfrom
Fragoler:docker
Open

DOCKERization!#99
Fragoler wants to merge 7 commits intospace-exodus:mainfrom
Fragoler:docker

Conversation

@Fragoler
Copy link

@Fragoler Fragoler commented Feb 14, 2026

About the PR

Добавлен пайплайн упаковки сервера в контейнер.
Триггерится при установки тега "vX.Y.Z"

Summary by CodeRabbit

  • Chores
    • Introduced Docker containerization for application packaging and deployment
    • Modernized CI/CD pipeline with updated tooling and Docker-centric release workflow
    • Optimized build configuration and removed legacy automated publishing processes
    • Added health monitoring to container for improved production reliability

@Fragoler Fragoler requested a review from Lokilife as a code owner February 14, 2026 00:35
@CLAassistant
Copy link

CLAassistant commented Feb 14, 2026

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link

coderabbitai bot commented Feb 14, 2026

📝 Walkthrough

Walkthrough

This PR containerizes the application by introducing Docker-based CI/CD infrastructure. It removes two deprecated GitHub Actions workflows, significantly overhauls the main publish workflow to use Docker container registry publishing with automated version tagging and release creation, and adds a multi-stage Dockerfile and .dockerignore for optimized builds.

Changes

Cohort / File(s) Summary
Docker Configuration
.dockerignore, Dockerfile
Added .dockerignore to exclude all root files except the release directory. New multi-stage Dockerfile builds a Debian-based runtime image, extracts the pre-built server binary from release artifacts, adds health checks, and configures the .NET runtime entrypoint.
GitHub Actions Workflows
.github/workflows/publish-changelog.yml, .github/workflows/publish-testing.yml
Removed deprecated workflows: publish-changelog.yml (automated changelog publishing) and publish-testing.yml (testing build and package pipeline).
Main Publish Workflow
.github/workflows/publish.yml
Completely refactored CI/CD pipeline to Docker-centric approach. Added version extraction from git tags, Docker Buildx setup, container registry login, metadata extraction for image tagging, and docker/build-push-action integration. Introduced release automation via ncipollo/release-action. Updated checkout and dotnet setup actions to latest versions. Consolidated packaging flow and removed legacy publishing scripts in favor of containerized deployment.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 A hop and a bound through Docker we go,
With containers and tags in a clean, versioned flow,
Old workflows retire, the new ones take flight,
From registry to release—the pipeline's now right! 🐇✨

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title "DOCKERization!" is vague and uses a colloquial, non-descriptive term that doesn't clearly convey what the pull request accomplishes. Consider using a more descriptive title like "Add Docker build pipeline for server packaging" that clearly explains the main change without relying on wordplay.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In @.github/workflows/publish.yml:
- Around line 37-46: The shell uses unquoted GitHub Actions expressions which
can lead to injection; wrap the interpolations in double quotes. Update the if
condition to quote ${{ github.ref }} (use "${{ github.ref }}"), and quote
expansions/assignments such as VERSION="${GITHUB_REF#refs/tags/}" and any uses
of ${VERSION} when echoing to GITHUB_OUTPUT; keep references to symbols
github.ref, GITHUB_REF, VERSION, and GITHUB_OUTPUT so you change the comparison
and assignment sites accordingly.
- Around line 103-106: The BUILD_DATE build-arg is being passed as a literal
shell expression; add a prior step that computes the timestamp and exposes it as
an output (e.g., a step with id "date" that writes build_date to
$GITHUB_OUTPUT), then use that output in the docker/build-push-action build-args
(replace the literal $(date ...) with ${{ steps.date.outputs.build_date }}),
keeping the existing VERSION and VCS_REF references unchanged.

In `@Dockerfile`:
- Around line 24-42: Add a non-root runtime user for the final stage: create a
dedicated user/group (e.g., "exodus") in the final stage (the stage using
mcr.microsoft.com/dotnet/runtime:9.0), chown the application directory (/app) so
that the new user owns the files copied by COPY --from=build /src/server/ ., and
add a USER instruction before ENTRYPOINT to run Robust.Server as that non-root
user; ensure any required runtime permissions are granted to that user so the
HEALTHCHECK and server can run.
- Around line 39-40: The HEALTHCHECK uses curl but the final image (FROM
mcr.microsoft.com/dotnet/runtime:9.0) is minimal and doesn't include curl, so
every check will fail; either install curl in the final stage by adding package
installation steps in the final stage Dockerfile (apt-get update && apt-get
install -y curl and cleanup) or replace the HEALTHCHECK command with a tool
present in the final image (e.g., a dotnet-based probe or wget if available), or
remove the HEALTHCHECK and move it to docker-compose/orchestrator; update the
HEALTHCHECK line (the CMD that calls curl -f http://localhost:1212/status ||
exit 1) accordingly to match the chosen approach.
🧹 Nitpick comments (3)
Dockerfile (1)

10-14: ca-certificates and curl are unnecessary in the build stage.

The build stage only needs unzip. The curl and ca-certificates packages are not used here (no downloads happen in this stage). Removing them will reduce build time and layer size.

Proposed fix
 RUN apt-get update && apt-get install -y --no-install-recommends \
     unzip \
-    ca-certificates \
-    curl \
     && rm -rf /var/lib/apt/lists/*
.github/workflows/publish.yml (2)

80-91: Semver tag patterns may produce no tags on workflow_dispatch.

When triggered via workflow_dispatch (not a tag push), steps.version.outputs.version is dev-<sha>, which is not valid semver. The type=semver patterns will silently produce nothing. Only type=ref,event=branch and possibly type=raw,value=latest will generate tags. This is likely fine but worth being aware of — if dispatched from a non-default branch, the only tag will be the branch name.

If a dev tag is always desired for non-tag runs, consider adding an explicit raw fallback:

          type=raw,value=dev,enable=${{ !startsWith(github.ref, 'refs/tags/') }}

108-118: Release step is well-guarded with the startsWith condition.

The release is correctly gated to only run on tag pushes.

One minor note: ncipollo/release-action@v1 is a major-version tag — consider pinning to a specific minor/patch (e.g., @v1.14.0) or using a commit SHA for reproducibility.

Comment on lines +37 to +46
run: |
if [[ ${{ github.ref }} == refs/tags/* ]]; then
VERSION=${GITHUB_REF#refs/tags/}
VERSION=${VERSION#v}
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "tag_with_v=v${VERSION}" >> $GITHUB_OUTPUT
else
echo "version=dev-${{ github.sha }}" >> $GITHUB_OUTPUT
echo "tag_with_v=dev" >> $GITHUB_OUTPUT
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Quote the expression to prevent potential shell injection.

${{ github.ref }} is interpolated directly into the shell script. While tag refs are unlikely to contain malicious characters, it's best practice to quote all GitHub Actions expressions to prevent injection.

Proposed fix
-        if [[ ${{ github.ref }} == refs/tags/* ]]; then
+        if [[ "${{ github.ref }}" == refs/tags/* ]]; then
🤖 Prompt for AI Agents
In @.github/workflows/publish.yml around lines 37 - 46, The shell uses unquoted
GitHub Actions expressions which can lead to injection; wrap the interpolations
in double quotes. Update the if condition to quote ${{ github.ref }} (use "${{
github.ref }}"), and quote expansions/assignments such as
VERSION="${GITHUB_REF#refs/tags/}" and any uses of ${VERSION} when echoing to
GITHUB_OUTPUT; keep references to symbols github.ref, GITHUB_REF, VERSION, and
GITHUB_OUTPUT so you change the comparison and assignment sites accordingly.

Comment on lines +103 to +106
build-args: |
VERSION=${{ steps.version.outputs.version }}
BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
VCS_REF=${{ github.sha }}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

BUILD_DATE build-arg passes a literal string, not the evaluated date.

In docker/build-push-action, the build-args input is not processed through a shell. The value $(date -u +'%Y-%m-%dT%H:%M:%SZ') will be passed as-is to Docker, so BUILD_DATE in the image label will be the literal string $(date -u +'%Y-%m-%dT%H:%M:%SZ') rather than an actual timestamp.

Compute the date in a prior step or use a GitHub Actions expression.

Proposed fix: compute the date in a prior step

Add a step before the Docker build:

    - name: Get build date
      id: date
      run: echo "build_date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT

Then reference it in build-args:

        build-args: |
          VERSION=${{ steps.version.outputs.version }}
-          BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
+          BUILD_DATE=${{ steps.date.outputs.build_date }}
          VCS_REF=${{ github.sha }}
🤖 Prompt for AI Agents
In @.github/workflows/publish.yml around lines 103 - 106, The BUILD_DATE
build-arg is being passed as a literal shell expression; add a prior step that
computes the timestamp and exposes it as an output (e.g., a step with id "date"
that writes build_date to $GITHUB_OUTPUT), then use that output in the
docker/build-push-action build-args (replace the literal $(date ...) with ${{
steps.date.outputs.build_date }}), keeping the existing VERSION and VCS_REF
references unchanged.

Comment on lines +24 to +42
FROM mcr.microsoft.com/dotnet/runtime:9.0 AS final
WORKDIR /app

ARG VERSION=dev
ARG BUILD_DATE
ARG VCS_REF

LABEL org.opencontainers.image.version="${VERSION}" \
org.opencontainers.image.created="${BUILD_DATE}" \
org.opencontainers.image.revision="${VCS_REF}" \
org.opencontainers.image.title="Exodus Monolith Server" \
org.opencontainers.image.description="SS14 Exodus Monolith Server"

COPY --from=build /src/server/ .

HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:1212/status || exit 1

ENTRYPOINT [ "./Robust.Server" ]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Container runs as root — add a non-root USER.

Trivy flagged DS-0002: the image runs everything as root. If the server is compromised, the attacker has full root privileges inside the container. Add a dedicated user for the runtime stage.

Proposed fix
 FROM mcr.microsoft.com/dotnet/runtime:9.0 AS final
 WORKDIR /app
 
+RUN groupadd -r ss14 && useradd -r -g ss14 -d /app ss14
+
 ARG VERSION=dev
 ARG BUILD_DATE
 ARG VCS_REF
 
 LABEL org.opencontainers.image.version="${VERSION}" \
       org.opencontainers.image.created="${BUILD_DATE}" \
       org.opencontainers.image.revision="${VCS_REF}" \
       org.opencontainers.image.title="Exodus Monolith Server" \
       org.opencontainers.image.description="SS14 Exodus Monolith Server"
 
 COPY --from=build /src/server/ .
+RUN chown -R ss14:ss14 /app
+USER ss14
 
 HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
     CMD curl -f http://localhost:1212/status || exit 1
 
 ENTRYPOINT [ "./Robust.Server" ]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
FROM mcr.microsoft.com/dotnet/runtime:9.0 AS final
WORKDIR /app
ARG VERSION=dev
ARG BUILD_DATE
ARG VCS_REF
LABEL org.opencontainers.image.version="${VERSION}" \
org.opencontainers.image.created="${BUILD_DATE}" \
org.opencontainers.image.revision="${VCS_REF}" \
org.opencontainers.image.title="Exodus Monolith Server" \
org.opencontainers.image.description="SS14 Exodus Monolith Server"
COPY --from=build /src/server/ .
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:1212/status || exit 1
ENTRYPOINT [ "./Robust.Server" ]
FROM mcr.microsoft.com/dotnet/runtime:9.0 AS final
WORKDIR /app
RUN groupadd -r ss14 && useradd -r -g ss14 -d /app ss14
ARG VERSION=dev
ARG BUILD_DATE
ARG VCS_REF
LABEL org.opencontainers.image.version="${VERSION}" \
org.opencontainers.image.created="${BUILD_DATE}" \
org.opencontainers.image.revision="${VCS_REF}" \
org.opencontainers.image.title="Exodus Monolith Server" \
org.opencontainers.image.description="SS14 Exodus Monolith Server"
COPY --from=build /src/server/ .
RUN chown -R ss14:ss14 /app
USER ss14
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:1212/status || exit 1
ENTRYPOINT [ "./Robust.Server" ]
🤖 Prompt for AI Agents
In `@Dockerfile` around lines 24 - 42, Add a non-root runtime user for the final
stage: create a dedicated user/group (e.g., "exodus") in the final stage (the
stage using mcr.microsoft.com/dotnet/runtime:9.0), chown the application
directory (/app) so that the new user owns the files copied by COPY --from=build
/src/server/ ., and add a USER instruction before ENTRYPOINT to run
Robust.Server as that non-root user; ensure any required runtime permissions are
granted to that user so the HEALTHCHECK and server can run.

Comment on lines +39 to +40
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:1212/status || exit 1
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

curl is not installed in the final stage — HEALTHCHECK will always fail.

The HEALTHCHECK uses curl, but curl was only installed in the build stage (debian). The final stage (mcr.microsoft.com/dotnet/runtime:9.0) is a minimal image that does not include curl. Every health check invocation will fail with "command not found," causing Docker/orchestrators to perpetually mark the container as unhealthy.

Either install curl in the final stage, or use a tool already available (e.g., a dotnet-based check or wget if present).

Option A: Install curl in the final stage
 FROM mcr.microsoft.com/dotnet/runtime:9.0 AS final
 WORKDIR /app
 
+RUN apt-get update && apt-get install -y --no-install-recommends curl \
+    && rm -rf /var/lib/apt/lists/*
+
 ARG VERSION=dev
Option B: Remove the HEALTHCHECK from the Dockerfile and define it in docker-compose or the orchestrator instead
-HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
-    CMD curl -f http://localhost:1212/status || exit 1
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:1212/status || exit 1
🤖 Prompt for AI Agents
In `@Dockerfile` around lines 39 - 40, The HEALTHCHECK uses curl but the final
image (FROM mcr.microsoft.com/dotnet/runtime:9.0) is minimal and doesn't include
curl, so every check will fail; either install curl in the final stage by adding
package installation steps in the final stage Dockerfile (apt-get update &&
apt-get install -y curl and cleanup) or replace the HEALTHCHECK command with a
tool present in the final image (e.g., a dotnet-based probe or wget if
available), or remove the HEALTHCHECK and move it to
docker-compose/orchestrator; update the HEALTHCHECK line (the CMD that calls
curl -f http://localhost:1212/status || exit 1) accordingly to match the chosen
approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments