From d51e33115a3f4c4ffdd3f4ef4028bf865d62b217 Mon Sep 17 00:00:00 2001 From: Heronimus Adie Date: Thu, 31 Aug 2023 14:25:18 +0700 Subject: [PATCH] chore(ci): build-test pipeline & release prebuilt images (#3) * chore(ci): init mage build & test pipeline * chore(ci): mage check - remove GOPRIVATE check, world-engine repo no longer private * chore(ci): ci remove unused registry variable * chore(ci): mage check - fix unused import * chore(ci): prep image release to container registry * chore(ci): fix workflow definition typo * chore(ci): image release to github container registry * chore(ci): image release - fix env var * chore(ci): image release - fix push command * chore(ci): image release - fix env ref * chore(ci): image release - released to new GCP Artifact Registry * chore(ci): image release - fix local image path * chore(ci): build - cache & permissions * chore(ci): docker-compose-prebuilt & README * chore(ci): compressed local images * chore(ci): dockerfile - use multistage docker build for smaller image size * chore(ci): conditional if for main/prod branch --- .github/workflows/backend-mage-pipeline.yaml | 143 +++++++++++++++++++ README.md | 28 ++++ cardinal/Dockerfile | 5 +- docker-compose-prebuilt.yml | 74 ++++++++++ magefiles/prereq.go | 17 --- 5 files changed, 249 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/backend-mage-pipeline.yaml create mode 100644 docker-compose-prebuilt.yml diff --git a/.github/workflows/backend-mage-pipeline.yaml b/.github/workflows/backend-mage-pipeline.yaml new file mode 100644 index 0000000..b2c2d55 --- /dev/null +++ b/.github/workflows/backend-mage-pipeline.yaml @@ -0,0 +1,143 @@ +name: template-mage-pipeline + +## workflow will trigger on below condition, +## except image release that have jobs condition to trigger only on tagging +on: + pull_request: + branches: + - main + push: + branches: + - main + tags: + - 'v*.*.*' + +env: + REGISTRY_URL: us-docker.pkg.dev + +jobs: + mage-build-test: + runs-on: ubuntu-latest + defaults: + run: + shell: bash + strategy: + matrix: + go-version: [1.20.x] + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Install Go + uses: actions/setup-go@v4 + with: + go-version: ${{ matrix.go-version }} + - uses: actions/cache@v3 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + - name: Mage - check + uses: magefile/mage-action@v2 + with: + version: latest + args: check + - name: Mage - build & test + uses: magefile/mage-action@v2 + with: + version: latest + args: test + - name: Docker show build images + run: | + docker image ls -a | grep starter-game-template + - name: Docker save local build images + if: startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main' + run: | + docker save ${{ github.event.repository.name }}-nakama:latest | gzip > /tmp/${{ github.event.repository.name }}-nakama-latest.tar.gz + docker save ${{ github.event.repository.name }}-cardinal:latest | gzip > /tmp/${{ github.event.repository.name }}-cardinal-latest.tar.gz + docker save ${{ github.event.repository.name }}-testsuite:latest | gzip > /tmp/${{ github.event.repository.name }}-testsuite-latest.tar.gz + - name: Upload local build images to temporary artifact + if: startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main' + uses: actions/upload-artifact@v3 + with: + name: buildimage + path: /tmp/starter-game-template-*.tar.gz + images-release: + runs-on: ubuntu-latest + needs: mage-build-test + if: startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main' + defaults: + run: + shell: bash + # Add "id-token" with the intended permissions. + permissions: + contents: 'read' + id-token: 'write' + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Download local build images artifact + uses: actions/download-artifact@v3 + with: + name: buildimage + path: /tmp/ + - name: Load image and show build images + run: | + docker load --input /tmp/${{ github.event.repository.name }}-nakama-latest.tar.gz + docker load --input /tmp/${{ github.event.repository.name }}-cardinal-latest.tar.gz + docker load --input /tmp/${{ github.event.repository.name }}-testsuite-latest.tar.gz + docker image ls -a | grep starter-game-template + - name: GCP auth + id: auth + uses: google-github-actions/auth@v1 + with: + workload_identity_provider: ${{ secrets.GCP_WIF_PROVIDER }} + service_account: ${{ secrets.GCP_WIF_SERVICE_ACCOUNT }} + - name: GCP - Set up Cloud SDK + uses: google-github-actions/setup-gcloud@v1 + with: + project_id: ${{ secrets.GCP_PROJECT_ID }} + - name: Docker - auth to artifact registry + run: | + gcloud auth configure-docker ${{ env.REGISTRY_URL }} + - name: Push image + run: | + IMAGE_ID_NAKAMA=${{ env.REGISTRY_URL }}/${{ github.repository_owner }}/${{ github.event.repository.name }}/nakama + IMAGE_ID_NAKAMA=$(echo $IMAGE_ID_NAKAMA | tr '[A-Z]' '[a-z]') + + IMAGE_ID_CARDINAL=${{ env.REGISTRY_URL }}/${{ github.repository_owner }}/${{ github.event.repository.name }}/cardinal + IMAGE_ID_CARDINAL=$(echo $IMAGE_ID_CARDINAL | tr '[A-Z]' '[a-z]') + + IMAGE_ID_TESTSUITE=${{ env.REGISTRY_URL }}/${{ github.repository_owner }}/${{ github.event.repository.name }}/testsuite + IMAGE_ID_TESTSUITE=$(echo $IMAGE_ID_TESTSUITE | tr '[A-Z]' '[a-z]') + + VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') + [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') + [ "$VERSION" == "main" ] && VERSION=latest + [ "$VERSION" == "merge" ] && VERSION=latest + + docker tag ${{ github.event.repository.name }}-nakama:latest $IMAGE_ID_NAKAMA:$VERSION + docker tag ${{ github.event.repository.name }}-cardinal:latest $IMAGE_ID_CARDINAL:$VERSION + docker tag ${{ github.event.repository.name }}-testsuite:latest $IMAGE_ID_TESTSUITE:$VERSION + + docker push $IMAGE_ID_NAKAMA:$VERSION + docker push $IMAGE_ID_CARDINAL:$VERSION + docker push $IMAGE_ID_TESTSUITE:$VERSION + artifact-cleanup: + runs-on: ubuntu-latest + needs: [ + mage-build-test, + images-release + ] + if: always() + steps: + - name: Remove local build image artifact + uses: geekyeggo/delete-artifact@v2 + with: + name: buildimage \ No newline at end of file diff --git a/README.md b/README.md index c61ca97..d8ac851 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,34 @@ Alternatively, killing the `mage start` process will also stop Nakama and Cardin Note, for now, if any Cardinal endpoints have been added or removed Nakama must be relaunched (via `mage stop` and `mage start`). We will add a future to hot reload this in the future. +# Running with the prebuilt Docker Images + +Prerequisites: +- Docker installed + +Docker Images Container Registry URLs: +- Cardinal: `us-docker.pkg.dev/argus-labs/starter-game-template/cardinal:` +- Nakama: `us-docker.pkg.dev/argus-labs/starter-game-template/nakama:` + + +To start the starter-game-template Nakama and Cardinal with prebuilt Docker Images: + +```bash +docker compose -f docker-compose-prebuilt.yml up --detach --wait +``` + +To check the services status & logs: + +```bash +docker compose -f docker-compose-prebuilt.yml ps +docker compose -f docker-compose-prebuilt.yml logs +``` + +To stop Nakama and Cardinal: +```bash +docker compose -f docker-compose-prebuilt.yml down +``` + # Verify the Server is Running Visit `localhost:7351` in a web browser to access Nakama. For local development, use `admin:password` as your login diff --git a/cardinal/Dockerfile b/cardinal/Dockerfile index 0dbeae2..bd8b1f1 100644 --- a/cardinal/Dockerfile +++ b/cardinal/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.20 +FROM golang:1.20 AS builder WORKDIR /usr/src/app @@ -7,6 +7,9 @@ copy vendor vendor/ RUN go build -v -o /usr/local/bin/app +FROM ubuntu:22.04 +COPY --from=builder /usr/local/bin/app /usr/local/bin/ + CMD ["app"] diff --git a/docker-compose-prebuilt.yml b/docker-compose-prebuilt.yml new file mode 100644 index 0000000..74b9b03 --- /dev/null +++ b/docker-compose-prebuilt.yml @@ -0,0 +1,74 @@ +version: "3" +services: + postgres: + command: postgres -c shared_preload_libraries=pg_stat_statements -c pg_stat_statements.track=all + environment: + - POSTGRES_DB=nakama + - POSTGRES_PASSWORD=localdb + expose: + - "5432" + image: postgres:12.2-alpine + ports: + - "5432:5432" + healthcheck: + test: ["CMD", "pg_isready", "-U", "postgres", "-d", "nakama"] + interval: 3s + timeout: 3s + retries: 5 + volumes: + - data:/var/lib/postgresql/data + redis: # This doesn't have the correct persistence settings. Don't use on for prod. + image: redis:latest + command: redis-server # TODO: This runs without password. Don't use for prod. + expose: + - "6379" + ports: + - "6379:6379" + restart: always + cardinal: + image: us-docker.pkg.dev/argus-labs/starter-game-template/cardinal:${STARTER_VERSION:-latest} + restart: unless-stopped + depends_on: + - redis + expose: + - "3333" + ports: + - "3333:3333" + environment: + - CARDINAL_PORT=3333 + - REDIS_ADDR=redis:6379 + - REDIS_MODE=normal + nakama: + image: us-docker.pkg.dev/argus-labs/starter-game-template/nakama:${STARTER_VERSION:-latest} + restart: unless-stopped + depends_on: + - postgres + - cardinal + environment: + - CARDINAL_ADDR=${CARDINAL_ADDR:-http://cardinal:3333} + - CARDINAL_NAMESPACE=0 + entrypoint: + - "/bin/sh" + - "-ecx" + - > + /nakama/nakama migrate up --database.address postgres:localdb@postgres:5432/nakama && + exec /nakama/nakama --config /nakama/data/local.yml --database.address postgres:localdb@postgres:5432/nakama + extra_hosts: + - "host.docker.internal:host-gateway" + expose: + - "7349" + - "7350" + - "7351" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:7350/"] + interval: 10s + timeout: 5s + retries: 5 + links: + - "postgres:db" + ports: + - "7349:7349" + - "7350:7350" + - "7351:7351" +volumes: + data: diff --git a/magefiles/prereq.go b/magefiles/prereq.go index 49a9ccd..6c3dca9 100644 --- a/magefiles/prereq.go +++ b/magefiles/prereq.go @@ -6,17 +6,10 @@ import ( "bytes" "errors" "fmt" - "strings" "github.com/magefile/mage/sh" ) -const ( - goprivateEnv = "GOPRIVATE" - goprivateURLArgusLabs = "github.com/argus-labs" - goprivateURLWorldEngine = goprivateURLArgusLabs + "/world-engine" -) - // allOutput runs the command and returns the stdout and stderr. Nothing is printed to stdout and stderr. func allOutput(cmd string, args ...string) (out string, err error) { outWriter, errWriter := &bytes.Buffer{}, &bytes.Buffer{} @@ -49,16 +42,6 @@ func checkPrereq(verbose bool) error { } } - check(goprivateEnv, func() error { - out, err := allOutput("go", "env", goprivateEnv) - if err != nil { - return fmt.Errorf("problem getting env variable %q", goprivateEnv) - } else if !strings.Contains(out, goprivateURLArgusLabs) { - return fmt.Errorf("the env variable %q should contain %q or %q", goprivateEnv, goprivateURLArgusLabs, goprivateURLWorldEngine) - } - return nil - }) - check("Docker", func() error { if _, err := allOutput("docker", "-v"); err != nil { return fmt.Errorf("docker is not installed: %v", err)