Skip to content

Merge branch 'dev' into gopi-dev #13

Merge branch 'dev' into gopi-dev

Merge branch 'dev' into gopi-dev #13

Workflow file for this run

name: deploy-ec2
on:
push:
branches: [ gopi-dev ]
permissions:
id-token: write
contents: read
env:
AWS_REGION: ${{ vars.AWS_REGION || 'us-east-1' }}
ECR_REPOSITORY: ${{ vars.ECR_REPOSITORY || 'careerforge' }}
EC2_INSTANCE_ID: ${{ vars.EC2_INSTANCE_ID }}
APP_PORT: "8080"
SERVICE_NAME: "careerforge"
jobs:
build-push-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
cache: maven
- name: Unit tests
working-directory: code/backend
run: mvn -B -ntp test
- name: Configure AWS credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
- name: Ensure ECR repo exists
run: |
set -e
aws ecr describe-repositories --repository-names "${ECR_REPOSITORY}" >/dev/null 2>&1 || \
aws ecr create-repository --repository-name "${ECR_REPOSITORY}"
- name: Login to ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Compute image tag
id: vars
run: |
echo "image=${{ steps.login-ecr.outputs.registry }}/${ECR_REPOSITORY}:${{ github.sha }}" >> "$GITHUB_OUTPUT"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push image
uses: docker/build-push-action@v6
with:
context: code/backend
file: code/backend/Dockerfile
push: true
tags: ${{ steps.vars.outputs.image }}
cache-from: type=gha
cache-to: type=gha,mode=max
# ---- Final deploy step (fixes region expansion & non-TTY login; Ubuntu 24.04-safe) ----
- name: Deploy on EC2 via SSM
env:
IMAGE: ${{ steps.vars.outputs.image }}
run: |
set -euo pipefail
# 1) Write a neutral script with placeholders so we can safely inject values
cat > deploy.sh <<'EOF'
#!/bin/sh
set -eu
REGION="__REGION__"
IMAGE="__IMAGE__"
SERVICE_NAME="__SERVICE_NAME__"
APP_PORT="__APP_PORT__"
# ---- Install Docker (Ubuntu path uses docker.asc; no gpg --dearmor / TTY) ----
if command -v apt-get >/dev/null 2>&1; then
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
# Remove conflicting Ubuntu docker/containerd packages (prevents "containerd.io : Conflicts: containerd")
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
apt-get remove -y "$pkg" || true
done
apt-get install -y ca-certificates curl unzip
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
. /etc/os-release
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $VERSION_CODENAME stable" > /etc/apt/sources.list.d/docker.list
apt-get update -y
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
elif command -v dnf >/dev/null 2>&1; then
dnf -y update || true
dnf -y install docker curl unzip || yum -y install docker curl unzip
elif command -v yum >/dev/null 2>&1; then
yum -y update || true
yum -y install docker curl unzip
else
echo "no supported package manager found"
exit 1
fi
systemctl enable --now docker || true
# ---- ECR login (non-interactive per AWS docs) ----
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
REGISTRY="${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com"
aws ecr get-login-password --region "${REGION}" \
| docker login --username AWS --password-stdin "${REGISTRY}"
# ---- Pull & run on host 80 -> container ${APP_PORT} ----
docker rm -f "${SERVICE_NAME}" || true
docker pull "${IMAGE}"
docker run -d --restart unless-stopped --name "${SERVICE_NAME}" -p 80:"${APP_PORT}" "${IMAGE}"
# ---- Evidence / health check ----
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Ports}}'
curl -sS -o /dev/null -w '%{http_code}\n' http://localhost/hello
EOF
chmod +x deploy.sh
# 2) Inject real values (this avoids single-quoted heredoc expansion issues)
sed -i "s|__REGION__|${{ env.AWS_REGION }}|g" deploy.sh
sed -i "s|__IMAGE__|${{ steps.vars.outputs.image }}|g" deploy.sh
sed -i "s|__SERVICE_NAME__|${{ env.SERVICE_NAME }}|g" deploy.sh
sed -i "s|__APP_PORT__|${{ env.APP_PORT }}|g" deploy.sh
# 3) Send to SSM (no YAML/JSON quoting headaches) and execute
B64=$(base64 -w0 deploy.sh || base64 deploy.sh | tr -d '\n')
CMD_ID=$(aws ssm send-command \
--instance-ids "${EC2_INSTANCE_ID}" \
--document-name "AWS-RunShellScript" \
--comment "Deploy ${SERVICE_NAME}" \
--parameters "commands=[\"echo ${B64} | base64 -d > /tmp/deploy.sh\",\"sudo sh /tmp/deploy.sh\"]" \
--query "Command.CommandId" --output text)
echo "CommandId: ${CMD_ID}"
# 4) Wait for completion and surface logs
for i in $(seq 1 30); do
STATUS=$(aws ssm get-command-invocation \
--command-id "$CMD_ID" \
--instance-id "${EC2_INSTANCE_ID}" \
--query "Status" --output text)
echo "SSM status: $STATUS"
case "$STATUS" in
Success) break ;;
Cancelled|Failed|TimedOut) break ;;
esac
sleep 5
done
aws ssm get-command-invocation \
--command-id "$CMD_ID" \
--instance-id "${EC2_INSTANCE_ID}" \
--query "{Status:Status, StdOut:StandardOutputContent, StdErr:StandardErrorContent}" \
--output text
[ "$STATUS" = "Success" ]