diff --git a/.github/workflows/production-deploy.yml b/.github/workflows/production-deploy.yml index e73db7b..8b995e3 100644 --- a/.github/workflows/production-deploy.yml +++ b/.github/workflows/production-deploy.yml @@ -1,26 +1,89 @@ name: production-deploy + on: push: branches: - master +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: - build: - name: Build + production-deploy: runs-on: ubuntu-latest + steps: - - name: Run deploy on production - uses: appleboy/ssh-action@v1.0.0 + - name: Check out latest commit + uses: actions/checkout@v3 + + - name: Log in to Docker Hub + uses: docker/login-action@v3 with: - host: ${{ secrets.SSH_HOST }} - username: ${{ secrets.SSH_USERNAME }} - key: ${{ secrets.SSH_KEY }} - port: ${{ secrets.SSH_PORT }} - script_stop: true - script: | - cd /home/akatsuki/akatsuki-api - git pull origin master - docker build -t akatsuki-api:latest . - cd /home/akatsuki/workbench - docker-compose stop akatsuki-api - docker-compose up -d akatsuki-api + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: osuAkatsuki/akatsuki-api + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile + push: true + tags: | + ${{ secrets.DOCKERHUB_USERNAME }}/akatsuki-api:latest + ${{ secrets.DOCKERHUB_USERNAME }}/akatsuki-api:${{ github.sha }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Get kubeconfig from github secrets + run: | + mkdir -p $HOME/.kube + echo "${{ secrets.KUBECONFIG }}" > $HOME/.kube/config + sudo chown $(id -u):$(id -g) $HOME/.kube/config + chmod 600 $HOME/.kube/config + + - name: Install helm + uses: azure/setup-helm@v3 + with: + version: "latest" + token: ${{ secrets.GITHUB_TOKEN }} + id: install + + - name: Install helm-diff + run: helm plugin install https://github.com/databus23/helm-diff + + - name: Checkout common-helm-charts repo + uses: actions/checkout@v3 + with: + repository: osuAkatsuki/common-helm-charts + token: ${{ secrets.COMMON_HELM_CHARTS_PAT }} + path: common-helm-charts + + - name: Clear pending deployments + run: | + kubectl delete secret -l 'status in (pending-install, pending-upgrade, pending-rollback),name=akatsuki-api-production' + + - name: Show manifest diff since previous release + run: | + helm diff upgrade \ + --allow-unreleased \ + --color=true \ + --values chart/values.yaml \ + akatsuki-api-production \ + common-helm-charts/microservice-base/ + + - name: Deploy service to production cluster + run: | + helm upgrade \ + --install \ + --atomic \ + --wait --timeout 10m \ + --cleanup-on-fail \ + --values chart/values.yaml \ + akatsuki-api-production \ + common-helm-charts/microservice-base/ diff --git a/Dockerfile b/Dockerfile index a850658..41f8e8d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,5 @@ FROM golang:1.20 -RUN apt update && apt install -y python3-pip WORKDIR /srv/root @@ -11,6 +10,9 @@ COPY . /srv/root RUN go build +RUN apt update && apt install -y python3-pip +RUN pip install --break-system-packages -i https://pypi2.akatsuki.gg/cmyui/dev akatsuki-cli + EXPOSE 80 CMD ["./scripts/start.sh"] diff --git a/app/start.go b/app/start.go index 3f7f927..e4a3e80 100644 --- a/app/start.go +++ b/app/start.go @@ -65,6 +65,8 @@ func Start(dbO *sqlx.DB) *fhr.Router { // v1 API { + r.Method("/_health", v1.HealthGET) + r.POSTMethod("/api/v1/tokens/self/delete", v1.TokenSelfDeletePOST) // Auth-free API endpoints (public data) diff --git a/app/v1/health.go b/app/v1/health.go new file mode 100644 index 0000000..7e29b34 --- /dev/null +++ b/app/v1/health.go @@ -0,0 +1,32 @@ +package v1 + +import ( + "github.com/osuAkatsuki/akatsuki-api/app/peppy" + "github.com/osuAkatsuki/akatsuki-api/common" +) + +type healthResponse struct { + common.ResponseBase +} + +func HealthGET(md common.MethodData) common.CodeMessager { + var r healthResponse + + err := peppy.R.Ping().Err() + if err != nil { + r.Code = 500 + r.Message = "redis error" + return r + } + + err = md.DB.Ping() + if err != nil { + r.Code = 500 + r.Message = "database error" + return r + } + + r.Code = 200 + r.Message = "healthy" + return r +} diff --git a/chart/values.yaml b/chart/values.yaml index c40edac..69ff2de 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -1,11 +1,35 @@ -app: - name: akatsuki-api - environment: staging - group: backend - container: - image: - repository: registry.digitalocean.com/akatsuki/akatsuki-api - tag: latest - imagePullSecrets: - - name: akatsuki - port: 80 +apps: + - name: akatsuki-api + environment: production + codebase: akatsuki-api + replicaCount: 1 + container: + image: + repository: osuakatsuki/akatsuki-api + tag: latest + port: 80 + env: + - name: APP_COMPONENT + value: api + readinessProbe: + httpGet: + path: /_health + port: 80 + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 3 + resources: + limits: + cpu: 300m + memory: 250Mi + requests: + cpu: 150m + memory: 150Mi + imagePullSecrets: + - name: osuakatsuki-registry-secret + # - name: registry-akatsuki + service: + type: ClusterIP + port: 80 diff --git a/scripts/start.sh b/scripts/start.sh index d4afa2a..4f2d1d5 100755 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -12,9 +12,8 @@ if [ -z "$APP_ENV" ]; then fi if [[ $PULL_SECRETS_FROM_VAULT -eq 1 ]]; then - # TODO: is there a better way to deal with this? - pip install --break-system-packages -i $PYPI_INDEX_URL akatsuki-cli - akatsuki vault get akatsuki-api $APP_ENV -o .env + # TODO: revert to $APP_ENV + akatsuki vault get akatsuki-api production-k8s -o .env source .env fi