Merge branch 'dev' into gopi-dev #13
This file contains hidden or 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
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" ] |