Fix for deploy-ec2.yml #10
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 | |
# ---- Robust SSM deploy (POSIX /bin/sh; Ubuntu 24.04-safe) ---- | |
- name: Deploy on EC2 via SSM | |
env: | |
IMAGE: ${{ steps.vars.outputs.image }} | |
run: | | |
set -euo pipefail | |
# Write the remote script locally (heredoc), then base64 it to avoid YAML/JSON escaping issues. | |
cat > deploy.sh <<'EOF' | |
#!/bin/sh | |
set -eu | |
# -------- Install Docker (Ubuntu path uses docker.asc; no gpg --dearmor) -------- | |
if command -v apt-get >/dev/null 2>&1; then | |
export DEBIAN_FRONTEND=noninteractive | |
apt-get update -y | |
# Remove conflicting Ubuntu packages to avoid "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 | |
# -------- Amazon Linux / RHEL family fallback -------- | |
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, pull latest, run on 80 -> ${APP_PORT} -------- | |
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) | |
REGION='${AWS_REGION}' | |
REGISTRY="${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com" | |
aws ecr get-login-password --region "${REGION}" \ | |
| docker login --username AWS --password-stdin "${REGISTRY}" | |
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 | |
# Send to SSM (two simple commands) 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}" | |
# 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" ] |