feat: implement Docker-based production deployment pipeline with automated Ansible provisioning, CI/CD workflows, and Caddy server configuration.
This commit is contained in:
30
.github/workflows/deploy-dev.yml
vendored
Normal file
30
.github/workflows/deploy-dev.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: Deploy to Dev
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Ansible and collections
|
||||
run: |
|
||||
pip install --break-system-packages ansible
|
||||
ansible-galaxy collection install ansible.posix community.docker
|
||||
|
||||
- name: Set up SSH key
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "${{ secrets.SRV_SSH_KEY }}" > ~/.ssh/deploy_key
|
||||
chmod 600 ~/.ssh/deploy_key
|
||||
|
||||
- name: Run Ansible playbook
|
||||
run: |
|
||||
ansible-playbook \
|
||||
-i infra/development/hosts.ini \
|
||||
-e "ansible_ssh_private_key_file=~/.ssh/deploy_key" \
|
||||
infra/development/site/deploy-playbook.yml
|
||||
32
.github/workflows/deploy-prod.yml
vendored
Normal file
32
.github/workflows/deploy-prod.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: Deploy to Production
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: main
|
||||
|
||||
- name: Install Ansible and collections
|
||||
run: |
|
||||
pip install --break-system-packages ansible
|
||||
ansible-galaxy collection install ansible.posix community.docker
|
||||
|
||||
- name: Set up SSH key
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "${{ secrets.SRV_SSH_KEY }}" > ~/.ssh/deploy_key
|
||||
chmod 600 ~/.ssh/deploy_key
|
||||
|
||||
- name: Run Ansible playbook
|
||||
run: |
|
||||
ansible-playbook \
|
||||
-i infra/production/hosts.ini \
|
||||
-e "ansible_ssh_private_key_file=~/.ssh/deploy_key" \
|
||||
infra/production/site/deploy-playbook.yml
|
||||
41
.github/workflows/on-create-tag.yml
vendored
Normal file
41
.github/workflows/on-create-tag.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: On Create Tag
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v[0-9]+.[0-9]+.[0-9]+'
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
uses: ./.github/workflows/publish-image.yml
|
||||
with:
|
||||
build_mode: production
|
||||
secrets: inherit
|
||||
|
||||
update-compose:
|
||||
needs: publish
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: main
|
||||
token: ${{ github.token }}
|
||||
|
||||
- name: Update image tag in production compose.yml
|
||||
run: |
|
||||
VERSION=${GITHUB_REF_NAME#v}
|
||||
sed -i "s|\(image:.*:\)[^[:space:]]*|\1${VERSION}|" infra/production/site/compose.yml
|
||||
|
||||
- name: Commit and push
|
||||
run: |
|
||||
git config user.name "respellion-bot"
|
||||
git config user.email "no-reply.git@respellion.nl"
|
||||
git add infra/production/site/compose.yml
|
||||
git commit -m "chore: update prod image to ${GITHUB_REF_NAME#v}"
|
||||
git push origin main
|
||||
|
||||
deploy-prod:
|
||||
needs: update-compose
|
||||
uses: ./.github/workflows/deploy-prod.yml
|
||||
secrets: inherit
|
||||
20
.github/workflows/on-pull-request-to-main.yml
vendored
Normal file
20
.github/workflows/on-pull-request-to-main.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: On Pull Request to Main
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
uses: ./.github/workflows/test.yml
|
||||
|
||||
publish:
|
||||
needs: test
|
||||
uses: ./.github/workflows/publish-image.yml
|
||||
secrets: inherit
|
||||
|
||||
deploy-dev:
|
||||
needs: publish
|
||||
uses: ./.github/workflows/deploy-dev.yml
|
||||
secrets: inherit
|
||||
21
.github/workflows/on-push-main.yml
vendored
Normal file
21
.github/workflows/on-push-main.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: On Push to Main
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
uses: ./.github/workflows/test.yml
|
||||
|
||||
publish:
|
||||
needs: test
|
||||
uses: ./.github/workflows/publish-image.yml
|
||||
with:
|
||||
build_mode: development
|
||||
secrets: inherit
|
||||
|
||||
deploy-dev:
|
||||
needs: publish
|
||||
uses: ./.github/workflows/deploy-dev.yml
|
||||
secrets: inherit
|
||||
56
.github/workflows/publish-image.yml
vendored
Normal file
56
.github/workflows/publish-image.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
name: Publish Image
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
build_mode:
|
||||
description: "Build mode (development or production)"
|
||||
type: string
|
||||
default: production
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
build_mode:
|
||||
description: "Build mode (development or production)"
|
||||
type: string
|
||||
default: production
|
||||
|
||||
env:
|
||||
REGISTRY: git.labs.respellion.tech
|
||||
IMAGE: respellion/learning-platform/learning-platform
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to the Container registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: respellion-bot
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE }}
|
||||
tags: |
|
||||
type=sha,format=short,prefix=
|
||||
type=raw,value=latest
|
||||
type=semver,pattern={{version}}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
BUILD_MODE=${{ inputs.build_mode }}
|
||||
48
.github/workflows/test.yml
vendored
Normal file
48
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: Test
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build Docker image
|
||||
run: docker build -t learning-platform .
|
||||
|
||||
- name: Build test image
|
||||
run: |
|
||||
cat > Dockerfile.test <<'EOF'
|
||||
FROM learning-platform
|
||||
COPY Caddyfile.test /etc/caddy/Caddyfile
|
||||
EOF
|
||||
docker build -t learning-platform-test -f Dockerfile.test .
|
||||
|
||||
- name: Start container
|
||||
run: |
|
||||
docker run -d --network gitea --name test-container learning-platform-test
|
||||
sleep 5
|
||||
|
||||
- name: Test homepage
|
||||
run: |
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" http://test-container)
|
||||
if [ "$status" != "200" ]; then
|
||||
echo "Homepage failed with status $status"
|
||||
exit 1
|
||||
fi
|
||||
echo "✓ Homepage OK"
|
||||
|
||||
- name: Test security headers
|
||||
run: |
|
||||
headers=$(curl -sI http://test-container)
|
||||
echo "$headers" | grep -q "X-Frame-Options" || (echo "Missing X-Frame-Options" && exit 1)
|
||||
echo "$headers" | grep -q "X-Content-Type-Options" || (echo "Missing X-Content-Type-Options" && exit 1)
|
||||
echo "✓ Security headers OK"
|
||||
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
run: docker stop test-container && docker rm test-container
|
||||
Reference in New Issue
Block a user