Skip to content

Deploy to production #13

Deploy to production

Deploy to production #13

name: Deploy to production
concurrency:
group: deploy-production
cancel-in-progress: false
on:
workflow_dispatch:
inputs:
tag:
description: "Tag to deploy"
required: true
jobs:
deploy:
environment: production
name: "Deploy to production [tag: ${{ inputs.tag }}]"
runs-on: ubuntu-24.04
env:
DOCKER_REGISTRY: registry.blumilk.pl
DOCKER_REGISTRY_USER_NAME: robot@blumilkbot-harbor
DOCKER_REGISTRY_PROJECT_NAME: internal-public
DOCKER_REGISTRY_REPO_NAME: lmt
TARGET_DIR_ON_SERVER: /blumilk/deployments/prod/projects
ENVIRONMENT: production
steps:
- name: checkout
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
fetch-tags: true
ref: ${{ inputs.tag }}
- name: set deployment project version
run: echo "DEPLOYMENT_PROJECT_VERSION=$(bash ./environment/.deployment/scripts/version.sh --long)" >> $GITHUB_ENV
- name: set docker image name
run: echo "DOCKER_IMAGE_NAME=${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_REGISTRY_PROJECT_NAME }}/${{ env.DOCKER_REGISTRY_REPO_NAME }}" >> $GITHUB_ENV
- name: fetch server secrets
uses: Infisical/[email protected]
with:
domain: https://infisical.blumilk.pl
client-id: ${{ secrets.INFISICAL_MACHINE_IDENTITY_GHA_BOT_CLIENT_ID }}
client-secret: ${{ secrets.INFISICAL_MACHINE_IDENTITY_GHA_BOT_CLIENT_SECRET }}
project-slug: blumilk-infra-pv-ih
env-slug: infra
secret-path: /servers/ovh/ns31445530
export-type: env
recursive: true
include-imports: true
- name: set up Docker Buildx
uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1
- name: login to Docker Registry
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with:
registry: ${{ env.DOCKER_REGISTRY }}
username: ${{ env.DOCKER_REGISTRY_USER_NAME }}
password: ${{ env.HARBOR_ROBOT_BLUMILKBOT_TOKEN }} # masked secret fetched from Infisical
- name: set docker app database image name
run: echo "DOCKER_APP_DATABASE_IMAGE_NAME=${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_REGISTRY_PROJECT_NAME }}/${{ env.DOCKER_REGISTRY_REPO_NAME }}-postgres" >> $GITHUB_ENV
- name: Docker meta for app database
id: meta-app-database
uses: docker/[email protected]
with:
images: |
${{ env.DOCKER_APP_DATABASE_IMAGE_NAME }}
tags: |
type=raw,value=${{ inputs.tag }}
type=raw,value=latest
context: workflow
- name: build and push app database image
uses: docker/[email protected]
with:
context: .
file: ./environment/.docker/postgres/Dockerfile
labels: ${{ steps.meta-app-database.outputs.labels }}
tags: ${{ steps.meta-app-database.outputs.tags }}
push: true
cache-from: type=registry,ref=${{ env.DOCKER_APP_DATABASE_IMAGE_NAME }}:build-cache
cache-to: type=registry,ref=${{ env.DOCKER_APP_DATABASE_IMAGE_NAME }}:build-cache,mode=max
- name: Docker meta for app
id: meta
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1
with:
images: ${{ env.DOCKER_IMAGE_NAME }}
tags: |
type=raw,value=${{ inputs.tag }}
type=raw,value=latest
context: workflow
- name: build and push app image
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5.4.0
with:
context: .
file: ./environment/.docker/app/Dockerfile
target: production
build-args: |
DEPLOYMENT_PROJECT_VERSION_ARG=${{ env.DEPLOYMENT_PROJECT_VERSION }}
ENVIRONMENT_ARG=${{ env.ENVIRONMENT }}
labels: ${{ steps.meta.outputs.labels }}
tags: ${{ steps.meta.outputs.tags }}
push: true
cache-from: type=registry,ref=${{ env.DOCKER_IMAGE_NAME }}:build-cache
cache-to: type=registry,ref=${{ env.DOCKER_IMAGE_NAME }}:build-cache,mode=max
- name: set deployment path on server
run: echo "DEPLOYMENT_PATH_ON_SERVER=${{ env.TARGET_DIR_ON_SERVER }}/${{ env.DOCKER_REGISTRY_PROJECT_NAME }}/${{ env.DOCKER_REGISTRY_REPO_NAME }}" >> $GITHUB_ENV
- name: copy files via ssh
uses: appleboy/scp-action@917f8b81dfc1ccd331fef9e2d61bdc6c8be94634 # v0.1.7
with:
timeout: 10s
command_timeout: 10m
host: ${{ env.SERVER_OVH_NS31445530_IP }} # masked secret fetched from Infisical
port: ${{ env.SERVER_OVH_NS31445530_SSH_PORT }} # masked secret fetched from Infisical
username: ${{ env.SERVER_OVH_NS31445530_BLUMILKBOT_USER_NAME }} # masked secret fetched from Infisical
key: ${{ env.SERVER_OVH_NS31445530_BLUMILKBOT_USER_SSH_PRIVATE_KEY }} # masked secret fetched from Infisical
passphrase: ${{ env.SERVER_OVH_NS31445530_BLUMILKBOT_USER_SSH_PRIVATE_KEY_PASSPHRASE }} # masked secret fetched from Infisical
source: "./environment/.deployment/production/*,./environment/.deployment/Taskfile.yml"
target: ${{ env.DEPLOYMENT_PATH_ON_SERVER }}
rm: true
- name: fetch project deployment secrets
uses: Infisical/[email protected]
with:
domain: https://infisical.blumilk.pl
client-id: ${{ secrets.INFISICAL_MACHINE_IDENTITY_GHA_BOT_CLIENT_ID }}
client-secret: ${{ secrets.INFISICAL_MACHINE_IDENTITY_GHA_BOT_CLIENT_SECRET }}
project-slug: lmt-d-hr8
env-slug: production
secret-path: /deployment
export-type: env
recursive: false
include-imports: false
- name: run deployment script over ssh
uses: appleboy/ssh-action@029f5b4aeeeb58fdfe1410a5d17f967dacf36262 # v1.0.3
with:
timeout: 10s
command_timeout: 10m
host: ${{ env.SERVER_OVH_NS31445530_IP }} # masked secret fetched from Infisical
port: ${{ env.SERVER_OVH_NS31445530_SSH_PORT }} # masked secret fetched from Infisical
username: ${{ env.SERVER_OVH_NS31445530_BLUMILKBOT_USER_NAME }} # masked secret fetched from Infisical
key: ${{ env.SERVER_OVH_NS31445530_BLUMILKBOT_USER_SSH_PRIVATE_KEY }} # masked secret fetched from Infisical
passphrase: ${{ env.SERVER_OVH_NS31445530_BLUMILKBOT_USER_SSH_PRIVATE_KEY_PASSPHRASE }} # masked secret fetched from Infisical
script_stop: true
# masked secrets from Infisical: HARBOR_ROBOT_BLUMILKBOT_TOKEN, SOPS_AGE_PRODUCTION_SECRET_KEY
script: |
cd ${{ env.DEPLOYMENT_PATH_ON_SERVER }}/environment/.deployment/
mv Taskfile.yml ${{ env.ENVIRONMENT }}/
cd ${{ env.ENVIRONMENT }}/
echo ${{ env.HARBOR_ROBOT_BLUMILKBOT_TOKEN }} | docker login ${{ env.DOCKER_REGISTRY }} --username ${{ env.DOCKER_REGISTRY_USER_NAME }} --password-stdin
export SOPS_AGE_KEY=${{ env.SOPS_AGE_PRODUCTION_SECRET_KEY }}
export ENVIRONMENT=${{ env.ENVIRONMENT }}
task deploy
docker images --filter dangling=true | grep "${{ env.DOCKER_IMAGE_NAME }}" | awk '{print $3}'| xargs --no-run-if-empty docker rmi
docker images --filter dangling=true | grep ${{ env.DOCKER_APP_DATABASE_IMAGE_NAME }} | awk '{print $3}'| xargs --no-run-if-empty docker rmi
docker logout ${{ env.DOCKER_REGISTRY }}