init
This commit is contained in:
commit
f0d13cd510
29 files changed
+6868
No files matched your search
@@ -0,0 +1,205 @@
|
||||
# This is a reusable Gitea Actions workflow.
|
||||
# It's designed to be called by other repositories to standardize the deployment process.
|
||||
# It performs two main jobs:
|
||||
# 1. Build: Builds a Docker image from the calling repository's Dockerfile and pushes it to a registry.
|
||||
# 2. Deploy: Runs the ansible-gitea playbook to deploy the newly built image to a target server.
|
||||
|
||||
name: Reusable CI/CD
|
||||
|
||||
# This workflow is triggered by a call from another workflow.
|
||||
on:
|
||||
workflow_call:
|
||||
# ------------------ INPUTS ------------------
|
||||
# These are parameters that the calling workflow must provide.
|
||||
inputs:
|
||||
# The name of the application/service being deployed.
|
||||
# Used to find project-specific variables in ansible.
|
||||
app_name:
|
||||
description: 'The application name'
|
||||
required: true
|
||||
type: string
|
||||
# The deployment environment (e.g., staging, production).
|
||||
deploy_env:
|
||||
description: 'The deployment environment'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
# ------------------ SECRETS ------------------
|
||||
# These are secrets that the calling workflow must pass.
|
||||
# They should be configured in the Gitea organization or repository settings.
|
||||
secrets:
|
||||
# Address of the target host(s) for Ansible.
|
||||
SERVER_HOST:
|
||||
description: 'Target hosts for Ansible (e.g., "user@host")'
|
||||
required: true
|
||||
SERVER_PORT:
|
||||
description: 'Target port for Ansible (e.g., "22")'
|
||||
required: false
|
||||
default: '22'
|
||||
SERVER_USER:
|
||||
description: 'Target user for Ansible (e.g., "cicd")'
|
||||
required: false
|
||||
default: 'cicd'
|
||||
# SSH private key to connect to the Ansible target host.
|
||||
SERVER_SSH_PRIVATE_KEY:
|
||||
description: 'SSH Private Key for Ansible'
|
||||
required: false
|
||||
# Password for the target host.
|
||||
SERVER_PASSWORD:
|
||||
description: 'Password for Ansible'
|
||||
required: false
|
||||
# Password for the Ansible vault.
|
||||
VAULT_PASSWORD:
|
||||
description: 'Ansible Vault Password'
|
||||
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.
|
||||
VAULT_ADDR:
|
||||
description: 'Vault server address (e.g., https://vault.example.com:8200)'
|
||||
required: true
|
||||
# The Vault role to use for authentication.
|
||||
VAULT_ROLE:
|
||||
description: 'Vault role for authentication'
|
||||
required: true
|
||||
# The path to the secrets in Vault (e.g., "secret/data/my-app my_secret").
|
||||
VAULT_SECRETS_PATH:
|
||||
description: 'Path to the secrets in Vault'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
# ============================================================================
|
||||
# JOB 1: BUILD AND PUSH DOCKER IMAGE
|
||||
# ============================================================================
|
||||
build:
|
||||
runs-on: alpine-latest
|
||||
# Grant permissions for the workflow to request an OIDC token.
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
outputs:
|
||||
image_tag: ${{ steps.meta.outputs.version }}
|
||||
image_name: ${{ secrets.DOCKER_REGISTRY }}/${{ github.repository_owner }}/${{ inputs.app_name }}
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Import 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: |
|
||||
${{ secrets.VAULT_SECRETS_PATH }} env_data | DOTENV_CONTENTS
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to Docker Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ secrets.DOCKER_REGISTRY }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ secrets.DOCKER_REGISTRY }}/${{ github.repository_owner }}/${{ inputs.app_name }}
|
||||
tags: |
|
||||
type=sha,prefix=,format=long
|
||||
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
secrets: |
|
||||
env=${{ steps.vault.outputs.DOTENV_CONTENTS }}
|
||||
|
||||
# ============================================================================
|
||||
# JOB 2: DEPLOY WITH ANSIBLE
|
||||
# ============================================================================
|
||||
deploy:
|
||||
runs-on: alpine-latest
|
||||
needs: build # This job runs only after the 'build' job succeeds.
|
||||
steps:
|
||||
- name: Checkout Application Code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Checkout Ansible Repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# This should be the path to your ansible-gitea repository
|
||||
repository: ${{ github.repository_owner }}/ansible-gitea
|
||||
path: .ansible
|
||||
|
||||
- name: Set up Ansible and Dependencies
|
||||
run: |
|
||||
apk add --no-cache openssh-client-default sshpass python3 py3-pip
|
||||
pip3 install ansible
|
||||
ansible-galaxy collection install community.docker
|
||||
|
||||
- name: Setup SSH
|
||||
if: ${{ secrets.SERVER_SSH_PRIVATE_KEY != '' }}
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "${{ secrets.SERVER_SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
# Disable strict host key checking for simplicity in CI
|
||||
echo "StrictHostKeyChecking no" >> ~/.ssh/config
|
||||
|
||||
- name: Setup Ansible Vault
|
||||
run: |
|
||||
echo "${{ secrets.VAULT_PASSWORD }}" > .ansible/.vault_pass
|
||||
|
||||
- name: Run Ansible Playbook
|
||||
working-directory: .ansible
|
||||
env:
|
||||
SERVER_HOST: ${{ secrets.SERVER_HOST }}
|
||||
SERVER_PASSWORD: ${{ secrets.SERVER_PASSWORD }}
|
||||
SERVER_SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_PRIVATE_KEY }}
|
||||
run: |
|
||||
auth_method_var=""
|
||||
if [[ -n "$SERVER_SSH_PRIVATE_KEY" ]]; then
|
||||
auth_method_var="auth_method=ssh_key ssh_key_path=/root/.ssh/id_rsa"
|
||||
if [[ -n "$SERVER_PASSWORD" ]]; then
|
||||
auth_method_var="$auth_method_var server_become_password=$SERVER_PASSWORD"
|
||||
fi
|
||||
elif [[ -n "$SERVER_PASSWORD" ]]; then
|
||||
auth_method_var="auth_method=password server_password=$SERVER_PASSWORD"
|
||||
auth_method_var="$auth_method_var server_become_password=$SERVER_PASSWORD"
|
||||
fi
|
||||
|
||||
ansible-playbook playbook.yml \
|
||||
-i "$SERVER_HOST," \
|
||||
--extra-vars "app_name=${{ inputs.app_name }} \
|
||||
deploy_env=${{ inputs.deploy_env }} \
|
||||
server_user=${{ inputs.server_user }} \
|
||||
server_port=${{ inputs.server_port }} \
|
||||
server_host=$SERVER_HOST \
|
||||
git_repo=${{ github.server_url }}/${{ github.repository }} \
|
||||
docker_image_tag=${{ needs.build.outputs.image_tag }} \
|
||||
docker_image_name=${{ needs.build.outputs.image_name }} \
|
||||
docker_image_full=${{ needs.build.outputs.image_name }}:${{ needs.build.outputs.image_tag }} \
|
||||
docker_registry=${{ secrets.DOCKER_REGISTRY }} \
|
||||
$auth_method_var" \
|
||||
--vault-password-file .vault_pass
|
||||
@@ -0,0 +1,36 @@
|
||||
# This is the main CI/CD workflow for the cms-api application.
|
||||
# It triggers on pushes of tags matching semantic versioning with environment suffixes.
|
||||
|
||||
name: CI/CD for project
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*' # Matches v-prefixed tags like v1.0.0, v1.0.0-dev.1, v1.0.0-stg.1
|
||||
|
||||
jobs:
|
||||
# This job calls the reusable deployment workflow.
|
||||
deploy_service:
|
||||
# Set the environment name based on the Git tag
|
||||
environment: ${{ (contains(github.ref_name, '-dev.')) && 'development' || (contains(github.ref_name, '-stg.')) && 'staging' || 'production' }}
|
||||
|
||||
uses: devops/ansible-gitea/.gitea/workflows/deploy.yml@main
|
||||
|
||||
# Provide the specific inputs for this application.
|
||||
with:
|
||||
app_name: ${{ github.event.repository.name }}
|
||||
deploy_env: ${{ (contains(github.ref_name, '-dev.')) && 'development' || (contains(github.ref_name, '-stg.')) && 'staging' || 'production' }}
|
||||
env_type: ${{ (contains(github.ref_name, 'worker')) && 'worker' || '' }}
|
||||
|
||||
# Pass the required secrets to the reusable workflow.
|
||||
# These secrets must be configured in the Gitea settings for this repository.
|
||||
secrets:
|
||||
SERVER_HOST: ${{ secrets.SERVER_HOST }}
|
||||
SERVER_PORT: ${{ secrets.SERVER_PORT }}
|
||||
SERVER_USER: ${{ secrets.SERVER_USER }}
|
||||
SERVER_SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_PRIVATE_KEY }}
|
||||
SERVER_PASSWORD: ${{ secrets.SERVER_PASSWORD }}
|
||||
VAULT_PASSWORD: ${{ secrets.VAULT_PASSWORD }}
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
DOCKER_REGISTRY: ${{ secrets.DOCKER_REGISTRY }}
|
||||
Reference in new issue
Block a user