-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
clinic: add deploy job to the github workflow
- Loading branch information
1 parent
a8c692e
commit ac17819
Showing
3 changed files
with
163 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,16 +5,17 @@ on: | |
- main | ||
tags: | ||
- "**" | ||
paths-ignore: | ||
- "**.md" | ||
paths: | ||
- clinic/** | ||
- .github/workflows/clinic.yaml | ||
pull_request: | ||
branches: | ||
- main | ||
|
||
env: | ||
JDK_DISTRIBUTION: temurin | ||
JAVA_VERSION: 21 | ||
NODE_VERSION: 21 | ||
NODE_VERSION: 20 | ||
|
||
jobs: | ||
tests: | ||
|
@@ -92,12 +93,17 @@ jobs: | |
npx shadow-cljs release app | ||
- name: Build Uberjar | ||
run: lein uberjar | ||
# buildx uses QEMU. Docker Buildx is needed for multiplatform build. | ||
- name: Set up QEMU | ||
uses: docker/setup-qemu-action@v3 | ||
- name: Set up Docker Buildx | ||
uses: docker/setup-buildx-action@v3 | ||
- name: Login to GitHub Container Registry | ||
uses: docker/login-action@v3 | ||
with: | ||
registry: ghcr.io | ||
username: ${{ github.actor }} | ||
password: ${{ secrets.GITHUB_TOKEN }} | ||
password: ${{ github.token }} | ||
- name: Generate Docker Image Tags | ||
id: docker-image-tags | ||
run: | | ||
|
@@ -112,4 +118,125 @@ jobs: | |
with: | ||
context: clinic | ||
push: true | ||
platforms: linux/amd64,linux/arm64 | ||
tags: ${{ steps.docker-image-tags.outputs.tags }} | ||
- name: Delete Untagged Images from GHCR | ||
uses: vlaurin/[email protected] | ||
with: | ||
container: ashutosh-onboarding/clinic | ||
token: ${{ github.token }} | ||
user: ${{ github.actor }} | ||
keep-last: 3 | ||
prune-untagged: true | ||
|
||
deploy: | ||
name: Deploy | ||
runs-on: ubuntu-latest | ||
timeout-minutes: 10 | ||
if: github.event_name == 'push' # skip for pull requests. | ||
needs: | ||
- build | ||
# GitHub won't allow using an env var to specify environment. | ||
environment: ${{ startsWith(github.ref, 'refs/tags/') && 'production' || 'staging' }} | ||
env: | ||
DEPLOYMENT_ID: ${{ startsWith(github.ref, 'refs/tags/') && 'production' || 'staging' }} | ||
SCP_DEST_PATH: /tmp/${{ github.sha }} | ||
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }} | ||
AWS_ACCESS_KEY_ID: ${{ secrets.DEPLOY_BOT_ACCESS_KEY }} | ||
defaults: | ||
run: | ||
working-directory: ./clinic | ||
steps: | ||
- name: Checkout Source | ||
uses: actions/checkout@v4 | ||
- name: Install prerequisites | ||
run: | | ||
sudo apt-get -qq update -y | ||
sudo apt-get -qq install -y awscli | ||
- name: Get Workflow Runner's Public IP | ||
id: workflow-runner-ip | ||
run: echo "ipv4=$(curl -s 'https://api.ipify.org')" >> "$GITHUB_OUTPUT" | ||
- name: Authorize runner's SSH access to EC2 host | ||
run: | | ||
aws ec2 authorize-security-group-ingress \ | ||
--group-id "$AWS_EC2_SG_ID" \ | ||
--protocol tcp \ | ||
--port 22 \ | ||
--cidr ${{ steps.workflow-runner-ip.outputs.ipv4 }}/32 | ||
env: | ||
AWS_SECRET_ACCESS_KEY: ${{ secrets.DEPLOY_BOT_SECRET_KEY }} | ||
AWS_EC2_SG_ID: ${{ secrets.AWS_EC2_SG_ID }} | ||
|
||
- name: Upload Systemd Service and Logrotate Config | ||
uses: appleboy/[email protected] | ||
with: | ||
host: ${{ secrets.SSH_HOST }} | ||
username: ${{ secrets.SSH_USER }} | ||
port: ${{ secrets.SSH_PORT }} | ||
key: ${{ secrets.SSH_KEY }} | ||
source: clinic/deploy/systemd,clinic/deploy/logrotate | ||
target: ${{ env.SCP_DEST_PATH }} | ||
strip_components: 2 # remove `clinic/deploy/` path component at target. | ||
rm: true # remove target directory before uploading data | ||
|
||
- name: Configure Deployment | ||
uses: appleboy/[email protected] | ||
env: | ||
APP_ENV: ${{ secrets.APP_ENV }} | ||
GHCR_USER: ${{ github.actor }} | ||
GHCR_TOKEN: ${{ github.token }} | ||
GHCR_IMAGE: ghcr.io/nilenso/ashutosh-onboarding/clinic:${{ env.DEPLOYMENT_ID == 'staging' && 'latest' || github.ref_name }} | ||
with: | ||
host: ${{ secrets.SSH_HOST }} | ||
username: ${{ secrets.SSH_USER }} | ||
port: ${{ secrets.SSH_PORT }} | ||
key: ${{ secrets.SSH_KEY }} | ||
# only pass sensitive env vars from here. for others, use GitHub's env | ||
# context, which is a little less error-prone. | ||
envs: APP_ENV,GHCR_TOKEN | ||
script_stop: true # stop script after first failure. | ||
script: | | ||
# stop existing deployment | ||
service_name="clinic@${{ env.DEPLOYMENT_ID }}.service" | ||
sudo systemctl stop "$service_name" || true | ||
# pull and tag the new docker image | ||
echo "$GHCR_TOKEN" | sudo docker login ghcr.io -u ${{ env.GHCR_USER }} --password-stdin | ||
sudo docker pull ${{ env.GHCR_IMAGE }} | ||
sudo docker tag ${{ env.GHCR_IMAGE }} clinic:${{ env.DEPLOYMENT_ID }} | ||
sudo docker logout ghcr.io | ||
# write environment configuration | ||
sudo mkdir -p /etc/clinic | ||
echo "$APP_ENV" | sudo tee "/etc/clinic/${{ env.DEPLOYMENT_ID }}.env" > /dev/null | ||
# update systemd unit | ||
sudo chown root:root ${{ env.SCP_DEST_PATH }}/systemd/* | ||
sudo chmod 644 ${{ env.SCP_DEST_PATH }}/systemd/* | ||
sudo mv ${{ env.SCP_DEST_PATH }}/systemd/* /etc/systemd/system/ | ||
# reload systemd daemon and restart the service | ||
sudo systemctl daemon-reload | ||
sudo systemctl reenable "$service_name" | ||
sudo systemctl restart "$service_name" | ||
# deploy logrotate config | ||
sudo chown root:root ${{ env.SCP_DEST_PATH }}/logrotate/* | ||
sudo chmod 644 ${{ env.SCP_DEST_PATH }}/logrotate/* | ||
sudo mv ${{ env.SCP_DEST_PATH }}/logrotate/* /etc/logrotate.d/ | ||
# clean-up | ||
sudo docker image prune -f | ||
sudo rm -rf ${{ env.SCP_DEST_PATH }} | ||
- name: Revoke runner's SSH access from EC2 host | ||
if: ${{ always() }} | ||
run: | | ||
aws ec2 revoke-security-group-ingress \ | ||
--group-id "$AWS_EC2_SG_ID" \ | ||
--protocol tcp \ | ||
--port 22 \ | ||
--cidr ${{ steps.workflow-runner-ip.outputs.ipv4 }}/32 | ||
env: | ||
AWS_SECRET_ACCESS_KEY: ${{ secrets.DEPLOY_BOT_SECRET_KEY }} | ||
AWS_EC2_SG_ID: ${{ secrets.AWS_EC2_SG_ID }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/var/log/clinic/*.log { | ||
daily | ||
rotate 30 | ||
copytruncate | ||
nocompress | ||
nodelaycompress | ||
notifempty | ||
missingok | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
[Unit] | ||
Description=Clinic %i | ||
After=docker.service hapi-%i.service | ||
Requires=docker.service hapi-%i.service | ||
|
||
[Service] | ||
Type=simple | ||
ExecStartPre=-docker stop %p-%i | ||
ExecStartPre=-docker rm %p-%i | ||
ExecStart=docker run --rm --name %p-%i \ | ||
--pull never \ | ||
--env-file /etc/clinic/%i.env \ | ||
--network host \ | ||
--memory 500M \ | ||
--cpus 0.25 \ | ||
clinic:%i | ||
StandardOutput=append:/var/log/clinic/%i.log | ||
StandardError=append:/var/log/clinic/%i.log | ||
SuccessExitStatus=130 | ||
Restart=on-failure | ||
|
||
[Install] | ||
WantedBy=default.target |