Fix for deploy-ec2.yml #5
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: ci-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 }} | |
- run: aws sts get-caller-identity | |
- name: Ensure ECR repo exists | |
run: | | |
aws ecr describe-repositories --repository-names "${{ env.ECR_REPOSITORY }}" >/dev/null 2>&1 || \ | |
aws ecr create-repository --repository-name "${{ env.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 }}/${{ env.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 | |
- name: Deploy on EC2 via SSM (robust, POSIX; installs AWS CLI v2 bundle) | |
env: | |
IMAGE: ${{ steps.vars.outputs.image }} | |
run: | | |
set -euo pipefail | |
cat > deploy.sh <<'EOF' | |
#!/bin/sh | |
set -eu | |
# ---- Install Docker (Ubuntu or Amazon Linux) ---- | |
if command -v apt-get >/dev/null 2>&1; then | |
export DEBIAN_FRONTEND=noninteractive | |
apt-get update -y | |
apt-get install -y docker.io curl unzip | |
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 | |
# ---- Install AWS CLI v2 (bundle) if missing ---- | |
if ! command -v aws >/dev/null 2>&1; then | |
ARCH="$(uname -m)" | |
case "$ARCH" in | |
x86_64) CLI_URL="https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" ;; | |
aarch64|arm64) CLI_URL="https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip" ;; | |
*) echo "unsupported arch: $ARCH"; exit 1 ;; | |
esac | |
curl -fsSL "$CLI_URL" -o /tmp/awscliv2.zip | |
unzip -q /tmp/awscliv2.zip -d /tmp | |
/tmp/aws/install | |
aws --version || { echo "aws cli install failed"; exit 1; } | |
fi | |
# ---- ECR login, pull, run ---- | |
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:8080 ${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 | |
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" | |
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" ] | |