Compare commits

...
4 Commits
Author SHA1 Message Date
Chu Văn Hải d333ec2988 up 2025-12-08 17:50:09 +07:00
Chu Văn Hải f7f5b534a8 up 2025-12-08 17:46:35 +07:00
Chu Văn Hải 6eb82fc05b up 2025-12-08 17:41:53 +07:00
Chu Văn Hải 39fd4049ad up 2025-12-08 17:28:31 +07:00
2 changed files with 84 additions and 47 deletions

No files matched your search

+70 -35
View File
@@ -23,6 +23,11 @@ on:
description: 'The deployment environment' description: 'The deployment environment'
required: true required: true
type: string type: string
# The environment type (e.g., worker).
env_type:
description: 'The environment type'
required: true
type: string
# ------------------ SECRETS ------------------ # ------------------ SECRETS ------------------
# These are secrets that the calling workflow must pass. # These are secrets that the calling workflow must pass.
@@ -52,18 +57,6 @@ on:
VAULT_PASSWORD: VAULT_PASSWORD:
description: 'Ansible Vault Password' description: 'Ansible Vault Password'
required: true required: true
# Docker registry username.
DOCKER_USERNAME:
description: 'Docker Registry Username'
required: true
# Docker registry password or token.
DOCKER_PASSWORD:
description: 'Docker Registry Password'
required: true
# The URL of the Docker registry.
DOCKER_REGISTRY:
description: 'Docker Registry URL'
required: true
# The address of the HashiCorp Vault server. # The address of the HashiCorp Vault server.
VAULT_ADDR: VAULT_ADDR:
description: 'Vault server address (e.g., https://vault.example.com:8200)' description: 'Vault server address (e.g., https://vault.example.com:8200)'
@@ -72,15 +65,16 @@ on:
VAULT_ROLE: VAULT_ROLE:
description: 'Vault role for authentication' description: 'Vault role for authentication'
required: true required: true
# The path to the secrets in Vault (e.g., "secret/data/my-app my_secret"). # The URL of the Docker registry.
VAULT_SECRETS_PATH: DOCKER_REGISTRY:
description: 'Path to the secrets in Vault' description: 'Docker Registry URL'
required: true required: true
type: string
jobs: jobs:
# ============================================================================ # =============================================================================
# JOB 1: PREPARE - AUTO-DETECT FRAMEWORK AND SETTINGS # JOB 1: PREPARE - AUTO-DETECT FRAMEWORK AND SETTINGS
# ============================================================================ # =============================================================================
prepare: prepare:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
outputs: outputs:
@@ -132,17 +126,17 @@ jobs:
BUILD_CMD="" BUILD_CMD=""
START_CMD="" START_CMD=""
if [ -f "package.json" ]; then if [ -f "package.json" ]; then
BUILD_CMD=$(grep -o '"build": "[^"]*"' package.json | sed 's/"build": "\(.*\)"/\1/' || echo "") BUILD_CMD=$(grep -o '"build": "[^"]*"' package.json | sed 's/"build": "\(.*\)"//' || echo "")
START_CMD=$(grep -o '"start": "[^"]*"' package.json | sed 's/"start": "\(.*\)"/\1/' || echo "") START_CMD=$(grep -o '"start": "[^"]*"' package.json | sed 's/"start": "\(.*\)"//' || echo "")
fi fi
echo "✓ Detected build command: ${BUILD_CMD}" echo "✓ Detected build command: ${BUILD_CMD}"
echo "✓ Detected start command: ${START_CMD}" echo "✓ Detected start command: ${START_CMD}"
echo "BUILD_COMMAND=${BUILD_CMD}" >> $GITEA_OUTPUT echo "BUILD_COMMAND=${BUILD_CMD}" >> $GITEA_OUTPUT
echo "START_COMMAND=${START_CMD}" >> $GITEA_OUTPUT echo "START_COMMAND=${START_CMD}" >> $GITEA_OUTPUT
# ============================================================================ # =============================================================================
# JOB 2: GENERATE DOCKERFILE # JOB 2: GENERATE DOCKERFILE
# ============================================================================ # =============================================================================
generate-dockerfile: generate-dockerfile:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
needs: prepare needs: prepare
@@ -166,9 +160,9 @@ jobs:
# For now, we assume a Dockerfile exists in the calling repo. # For now, we assume a Dockerfile exists in the calling repo.
echo "dockerfile_path=./Dockerfile" >> $GITEA_OUTPUT echo "dockerfile_path=./Dockerfile" >> $GITEA_OUTPUT
# ============================================================================ # =============================================================================
# JOB 3: BUILD AND PUSH DOCKER IMAGE # JOB 3: BUILD AND PUSH DOCKER IMAGE
# ============================================================================ # =============================================================================
build: build:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
needs: [prepare, generate-dockerfile] needs: [prepare, generate-dockerfile]
@@ -178,7 +172,7 @@ jobs:
contents: read contents: read
outputs: outputs:
image_tag: ${{ steps.meta.outputs.version }} image_tag: ${{ steps.meta.outputs.version }}
image_name: ${{ secrets.DOCKER_REGISTRY }}/${{ github.repository_owner }}/${{ inputs.app_name }} image_name: ${{ inputs.DOCKER_REGISTRY }}/${{ github.repository_owner }}/${{ inputs.app_name }}
steps: steps:
- name: Checkout Code - name: Checkout Code
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -192,23 +186,23 @@ jobs:
method: jwt method: jwt
jwt: ${{ job.id_token }} jwt: ${{ job.id_token }}
secrets: | secrets: |
${{ secrets.VAULT_SECRETS_PATH }} env_data | DOTENV_CONTENTS secret/data/${{ inputs.app_name }}/${{ inputs.deploy_env }} * | DOTENV_CONTENTS
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: Log in to Docker Registry - name: Log in to Gitea's Docker Registry
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:
registry: ${{ secrets.DOCKER_REGISTRY }} registry: ${{ inputs.DOCKER_REGISTRY }}
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ gitea.actor }}
password: ${{ secrets.DOCKER_PASSWORD }} password: ${{ secrets.token }}
- name: Docker metadata - name: Docker metadata
id: meta id: meta
uses: docker/metadata-action@v5 uses: docker/metadata-action@v5
with: with:
images: ${{ secrets.DOCKER_REGISTRY }}/${{ github.repository_owner }}/${{ inputs.app_name }} images: ${{ inputs.DOCKER_REGISTRY }}/${{ github.repository_owner }}/${{ inputs.app_name }}
tags: | tags: |
type=sha,prefix=,format=long type=sha,prefix=,format=long
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
@@ -224,12 +218,15 @@ jobs:
secrets: | secrets: |
env=${{ steps.vault.outputs.DOTENV_CONTENTS }} env=${{ steps.vault.outputs.DOTENV_CONTENTS }}
# ============================================================================ # =============================================================================
# JOB 4: DEPLOY WITH ANSIBLE # JOB 4: DEPLOY WITH ANSIBLE
# ============================================================================ # =============================================================================
deploy: deploy:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
needs: [prepare, build] # This job runs only after 'prepare' and 'build' jobs succeed. needs: [prepare, build] # This job runs only after 'prepare' and 'build' jobs succeed.
permissions:
id-token: write
contents: read
steps: steps:
- name: Checkout Application Code - name: Checkout Application Code
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -257,8 +254,27 @@ jobs:
echo "StrictHostKeyChecking no" >> ~/.ssh/config echo "StrictHostKeyChecking no" >> ~/.ssh/config
- name: Setup Ansible Vault - name: Setup Ansible Vault
working-directory: .ansible
run: | run: |
echo "${{ secrets.VAULT_PASSWORD }}" > .ansible/.vault_pass echo "${{ secrets.VAULT_PASSWORD }}" > .vault_pass
- name: Import App Secrets from HashiCorp Vault
id: vault
uses: hashicorp/vault-action@v2
with:
url: ${{ secrets.VAULT_ADDR }}
role: ${{ secrets.VAULT_ROLE }}
method: jwt
jwt: ${{ job.id_token }}
secrets: |
secret/data/${{ inputs.app_name }}/${{ inputs.deploy_env }} * | app_secrets
- name: Create Ansible secret file
run: |
ANSIBLE_PROJECT_DIR=".ansible/projects/${{ inputs.app_name }}"
mkdir -p "${ANSIBLE_PROJECT_DIR}/templates"
echo "${{ steps.vault.outputs.app_secrets }}" > "${ANSIBLE_PROJECT_DIR}/templates/.env.j2"
echo "✅ Created .env.j2 for Ansible"
- name: Run Ansible Playbook - name: Run Ansible Playbook
working-directory: .ansible working-directory: .ansible
@@ -282,8 +298,8 @@ jobs:
-i "$SERVER_HOST," \ -i "$SERVER_HOST," \
--extra-vars "app_name=${{ inputs.app_name }} \ --extra-vars "app_name=${{ inputs.app_name }} \
deploy_env=${{ inputs.deploy_env }} \ deploy_env=${{ inputs.deploy_env }} \
server_user=${{ inputs.server_user }} \ server_user=${{ secrets.SERVER_USER }} \
server_port=${{ inputs.server_port }} \ server_port=${{ secrets.SERVER_PORT }} \
server_host=$SERVER_HOST \ server_host=$SERVER_HOST \
git_repo=${{ github.server_url }}/${{ github.repository }} \ git_repo=${{ github.server_url }}/${{ github.repository }} \
framework=${{ needs.prepare.outputs.framework }} \ framework=${{ needs.prepare.outputs.framework }} \
@@ -293,3 +309,22 @@ jobs:
docker_registry=${{ secrets.DOCKER_REGISTRY }} \ docker_registry=${{ secrets.DOCKER_REGISTRY }} \
$auth_method_var" \ $auth_method_var" \
--vault-password-file .vault_pass --vault-password-file .vault_pass
cleanup:
name: Cleanup old images
runs-on: ubuntu-22.04
needs: deploy
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Clean up old Docker images and cache
run: |
echo "🧹 Cleaning up old Docker images and build cache..."
# Prune images older than 7 days (168 hours)
docker image prune -af --filter "until=168h" || echo "Docker image prune failed, continuing."
# Prune buildx cache
docker buildx prune -af --filter "until=168h" || echo "Docker buildx prune failed, continuing."
echo "✅ Cleanup finished."
+14 -12
View File
@@ -11,26 +11,28 @@ on:
jobs: jobs:
# This job calls the reusable deployment workflow. # This job calls the reusable deployment workflow.
deploy_service: deploy_service:
# Set the environment name based on the Git tag # Set the environment name based on the Git tag. Default is 'development'.
environment: ${{ (contains(github.ref_name, '-dev.')) && 'development' || (contains(github.ref_name, '-stg.')) && 'staging' || 'production' }} environment: ${{ (contains(github.ref_name, '-stg.')) && 'staging' || (contains(github.ref_name, '-prod.')) && 'production' || 'development' }}
uses: devops/ansible-gitea/.gitea/workflows/deploy.yml@main uses: devops/ansible-gitea/.gitea/workflows/deploy.yml@main
# Provide the specific inputs for this application. # Provide the specific inputs for this application.
with: with:
app_name: ${{ github.event.repository.name }} app_name: ${{ github.event.repository.name }}
deploy_env: ${{ (contains(github.ref_name, '-dev.')) && 'development' || (contains(github.ref_name, '-stg.')) && 'staging' || 'production' }} # Set deploy_env based on the Git tag. Default is 'development'.
deploy_env: ${{ (contains(github.ref_name, '-stg.')) && 'staging' || (contains(github.ref_name, '-prod.')) && 'production' || 'development' }}
env_type: ${{ (contains(github.ref_name, 'worker')) && 'worker' || '' }} env_type: ${{ (contains(github.ref_name, 'worker')) && 'worker' || '' }}
# Pass the required secrets to the reusable workflow. # Pass the required secrets to the reusable workflow.
# These secrets must be configured in the Gitea settings for this repository. # These secrets must be configured in the Gitea settings for this repository
# with suffixes _DEV, _STG, _PROD. The workflow defaults to _DEV secrets.
secrets: secrets:
SERVER_HOST: ${{ secrets.SERVER_HOST }} SERVER_HOST: ${{ (contains(github.ref_name, '-stg.')) && vars.SERVER_HOST_STG || (contains(github.ref_name, '-prod.')) && vars.SERVER_HOST_PROD || vars.SERVER_HOST_DEV || 'localhost' }}
SERVER_PORT: ${{ secrets.SERVER_PORT }} SERVER_PORT: ${{ (contains(github.ref_name, '-stg.')) && vars.SERVER_PORT_STG || (contains(github.ref_name, '-prod.')) && vars.SERVER_PORT_PROD || vars.SERVER_PORT_DEV || '22' }}
SERVER_USER: ${{ secrets.SERVER_USER }} SERVER_USER: ${{ (contains(github.ref_name, '-stg.')) && vars.SERVER_USER_STG || (contains(github.ref_name, '-prod.')) && vars.SERVER_USER_PROD || vars.SERVER_USER_DEV || 'cicd' }}
SERVER_SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_PRIVATE_KEY }} SERVER_SSH_PRIVATE_KEY: ${{ (contains(github.ref_name, '-stg.')) && secrets.SERVER_SSH_PRIVATE_KEY_STG || (contains(github.ref_name, '-prod.')) && secrets.SERVER_SSH_PRIVATE_KEY_PROD || secrets.SERVER_SSH_PRIVATE_KEY_DEV || '' }}
SERVER_PASSWORD: ${{ secrets.SERVER_PASSWORD }} SERVER_PASSWORD: ${{ (contains(github.ref_name, '-stg.')) && secrets.SERVER_PASSWORD_STG || (contains(github.ref_name, '-prod.')) && secrets.SERVER_PASSWORD_PROD || secrets.SERVER_PASSWORD_DEV || '' }}
VAULT_PASSWORD: ${{ secrets.VAULT_PASSWORD }} VAULT_PASSWORD: ${{ secrets.VAULT_PASSWORD }}
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} VAULT_ROLE: ${{ vars.VAULT_ROLE }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} VAULT_ADDR: ${{ vars.VAULT_ADDR || 'https://vault.nguoiduathu.eu.org' }}
DOCKER_REGISTRY: ${{ secrets.DOCKER_REGISTRY }} DOCKER_REGISTRY: ${{ vars.DOCKER_REGISTRY || github.server_url }}