diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml new file mode 100644 index 0000000..01a18f6 --- /dev/null +++ b/.gitea/workflows/deploy.yml @@ -0,0 +1,56 @@ +name: Build and Deploy + +on: + push: + branches: [main] + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build: + name: Build & Push Image + runs-on: self-hosted + permissions: + contents: read + packages: write + outputs: + image-digest: ${{ steps.build.outputs.digest }} + + steps: + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push image + id: build + run: | + IMAGE="alexmickelson/cobblemon:${{ github.run_number }}" + docker build --push -t "${IMAGE}" . + + - name: Deploy + run: | + IMAGE="alexmickelson/cobblemon:${{ github.run_number }}" + + kubectl get secret cobblemon-ui-secret --namespace=cobblemon 2>/dev/null || \ + kubectl create secret generic cobblemon-ui-secret \ + --namespace=cobblemon \ + --from-literal=secret-key-base="${{ secrets.SECRET_KEY_BASE }}" + + for file in k8s/*.yaml; do + envsubst < "$file" | kubectl apply -f - + done + + kubectl rollout status deployment/cobblemon-ui \ + --namespace=cobblemon \ + --timeout=5m diff --git a/Dockerfile b/Dockerfile index 6da12c0..8070593 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,27 +1,52 @@ -FROM hexpm/elixir:1.18.4-erlang-26.2.5.18-debian-bookworm-20260223-slim +# ---- Build stage ---- +FROM hexpm/elixir:1.18.4-erlang-26.2.5.18-debian-bookworm-20260223-slim AS builder -RUN apt-get update && apt-get install -y \ +RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ git \ curl \ - inotify-tools \ && rm -rf /var/lib/apt/lists/* WORKDIR /app -RUN mix local.hex --force && \ - mix local.rebar --force +RUN mix local.hex --force && mix local.rebar --force + +ENV MIX_ENV=prod COPY mix.exs mix.lock ./ -RUN mix deps.get +RUN mix deps.get --only prod +RUN mix deps.compile COPY config config COPY assets assets -COPY lib lib COPY priv priv +COPY lib lib -RUN mix assets.setup +RUN mix assets.setup && mix assets.deploy +RUN mix compile && mix release +# ---- Runtime stage ---- +FROM debian:bookworm-slim AS runtime + +RUN apt-get update && apt-get install -y --no-install-recommends \ + libstdc++6 \ + openssl \ + libncurses5 \ + locales \ + ca-certificates \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen +ENV LANG=en_US.UTF-8 + +WORKDIR /app +RUN chown nobody /app + +COPY --from=builder --chown=nobody:root /app/_build/prod/rel/cobblemon_ui ./ + +USER nobody + +ENV PHX_SERVER=true EXPOSE 4000 -CMD ["mix", "phx.server"] +CMD ["/app/bin/cobblemon_ui", "start"] diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml new file mode 100644 index 0000000..f9a1115 --- /dev/null +++ b/k8s/deployment.yaml @@ -0,0 +1,65 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: cobblemon-ui + namespace: minecraft + labels: + app: cobblemon-ui +spec: + replicas: 1 + selector: + matchLabels: + app: cobblemon-ui + template: + metadata: + labels: + app: cobblemon-ui + spec: + containers: + - name: cobblemon-ui + image: $IMAGE + ports: + - name: http + containerPort: 4000 + env: + - name: PHX_SERVER + value: "true" + - name: PHX_HOST + value: "cobblemon.alexmickelson.guru" + - name: PORT + value: "4000" + - name: SECRET_KEY_BASE + valueFrom: + secretKeyRef: + name: cobblemon-ui-secret + key: secret-key-base + volumeMounts: + - name: cobblemon-data + mountPath: /cobblemon-data + readOnly: true + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + readinessProbe: + httpGet: + path: / + port: 4000 + initialDelaySeconds: 10 + periodSeconds: 10 + failureThreshold: 3 + livenessProbe: + httpGet: + path: / + port: 4000 + initialDelaySeconds: 30 + periodSeconds: 30 + failureThreshold: 3 + volumes: + - name: cobblemon-data + hostPath: + path: /data/minecraft/cobblemon-data + type: Directory diff --git a/k8s/ingress.yaml b/k8s/ingress.yaml new file mode 100644 index 0000000..0836849 --- /dev/null +++ b/k8s/ingress.yaml @@ -0,0 +1,18 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: cobblemon-ui + namespace: minecraft +spec: + ingressClassName: nginx + rules: + - host: cobblemon.alexmickelson.guru + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: cobblemon-ui + port: + number: 80 diff --git a/k8s/service.yaml b/k8s/service.yaml new file mode 100644 index 0000000..3d6d55e --- /dev/null +++ b/k8s/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: cobblemon-ui + namespace: minecraft + labels: + app: cobblemon-ui +spec: + selector: + app: cobblemon-ui + ports: + - name: http + port: 80 + targetPort: 4000