-
Notifications
You must be signed in to change notification settings - Fork 2
OpenTofu infra for deploying on ec2 #232
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
27d0ff6
5e5cc5b
e91eb06
ec83f25
453f95e
4d93d8d
43916a5
521e750
05fcd1b
76b4ab0
5fb47f5
942ea13
c83e88c
3e60eaa
cddcf48
bd97aac
fd1ec89
7f91476
60d0dcc
e8e2c00
1d46d36
476f04b
1d13c2d
aa5786e
e5f6998
d55fbfe
d26b090
dda7f30
cedfa41
52c174b
ef93a8e
7cca80b
763cc13
728a1b8
4b16ff5
8f3efe4
3a8e9ab
87c5b21
130d0fb
3513e94
0f25d03
2c28abd
49ddfa5
ac50543
4df94c8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| # source: https://docs.github.com/en/actions/tutorials/publish-packages/publish-docker-images#publishing-images-to-docker-hub-and-github-packages | ||
| name: Create and publish a Docker image | ||
|
|
||
| # manually trigger while testing | ||
| on: | ||
| push: | ||
| branches: | ||
| - main | ||
| workflow_dispatch: | ||
|
|
||
| # Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds. | ||
| env: | ||
| REGISTRY: ghcr.io | ||
|
|
||
| jobs: | ||
| build-and-push-image: | ||
| runs-on: ubuntu-latest | ||
| # Sets the permissions granted to the `PACKAGE_TOKEN` for the actions in this job. | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
| attestations: write | ||
| id-token: write | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v5 | ||
| # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. | ||
| - name: Log in to the Container registry | ||
| uses: docker/login-action@v3 | ||
| with: | ||
| registry: ${{ env.REGISTRY }} | ||
| username: ${{ github.actor }} | ||
| password: ${{ secrets.PACKAGE_TOKEN }} | ||
| # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. | ||
| - name: Set lowercase image name | ||
| run: | | ||
| IMAGE_NAME=$(echo "${GITHUB_REPOSITORY}" | tr '[:upper:]' '[:lower:]') | ||
| echo "IMAGE_NAME=${IMAGE_NAME}" >> $GITHUB_ENV | ||
| - name: Extract metadata (tags, labels) for Docker | ||
| id: meta | ||
| uses: docker/metadata-action@v5 | ||
| with: | ||
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | ||
| # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. | ||
| # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see [Usage](https://github.com/docker/build-push-action#usage) in the README of the `docker/build-push-action` repository. | ||
| # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. | ||
|
|
||
| - name: Build and push web Docker image | ||
| id: push | ||
| uses: docker/build-push-action@v6 | ||
| with: | ||
| context: ./TEKDB | ||
| file: ./TEKDB/Dockerfile | ||
| push: true | ||
| tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/web:latest,${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/web:${{ github.sha }} | ||
| labels: ${{ steps.meta.outputs.labels }} | ||
| - name: Build and push proxy Docker image | ||
| id: push-proxy | ||
| uses: docker/build-push-action@v6 | ||
| with: | ||
| context: ./proxy | ||
| file: ./proxy/Dockerfile | ||
| push: true | ||
| tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/proxy:latest,${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/proxy:${{ github.sha }} | ||
| labels: ${{ steps.meta.outputs.labels }} | ||
|
|
||
| # This step generates an artifact attestation for the image, which is an unforgeable statement about where and how it was built. It increases supply chain security for people who consume the image. For more information, see [Using artifact attestations to establish provenance for builds](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds). | ||
| - name: Generate artifact attestation for web image | ||
| uses: actions/attest-build-provenance@v3 | ||
| with: | ||
| subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/web | ||
| subject-digest: ${{ steps.push.outputs.digest }} | ||
| push-to-registry: true | ||
| - name: Generate artifact attestation for proxy image | ||
| uses: actions/attest-build-provenance@v3 | ||
| with: | ||
| subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/proxy | ||
| subject-digest: ${{ steps.push-proxy.outputs.digest }} | ||
| push-to-registry: true | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| name: Build, Push, and Deploy to EC2 Staging | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| - develop | ||
|
Comment on lines
+3
to
+6
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. changed to deploy to ec2 staging on push to the develop branch. Need to add to the ec2 user data script to switch to the develop branch. But this needs to be merged first. kind of a 🐔 and 🥚 situation |
||
| workflow_dispatch: | ||
|
|
||
| jobs: | ||
| build-push-and-deploy: | ||
| name: Build, Push to ECR, Deploy to EC2 Staging | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| id-token: write | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v5 | ||
|
|
||
| - name: Configure AWS credentials | ||
| uses: aws-actions/configure-aws-credentials@v5 | ||
| with: | ||
| role-to-assume: ${{ secrets.AWS_ROLE_ARN }} | ||
| aws-region: ${{ secrets.AWS_REGION}} | ||
|
|
||
| - name: Login to Amazon ECR | ||
| id: login-ecr | ||
| uses: aws-actions/amazon-ecr-login@v2 | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@v3 | ||
|
|
||
| - name: Build, tag, and push web Docker image to ECR | ||
| id: build-web-image | ||
| env: | ||
| IMAGE_TAG: ${{ github.sha }} | ||
| IMAGE_URI: ${{ secrets.WEB_ECR_IMAGE_URI }} | ||
| run: | | ||
| docker buildx build \ | ||
| --platform linux/amd64,linux/arm64 \ | ||
| -t $IMAGE_URI:$IMAGE_TAG \ | ||
| -t $IMAGE_URI:latest \ | ||
| -f ./TEKDB/Dockerfile ./TEKDB \ | ||
| --push | ||
|
|
||
| - name: Build, tag, and push proxy Docker image to ECR | ||
| id: build-proxy-image | ||
| env: | ||
| IMAGE_TAG: ${{ github.sha }} | ||
| IMAGE_URI: ${{ secrets.PROXY_ECR_IMAGE_URI }} | ||
| run: | | ||
| docker buildx build \ | ||
| --platform linux/amd64,linux/arm64 \ | ||
| -t $IMAGE_URI:$IMAGE_TAG \ | ||
| -t $IMAGE_URI:latest \ | ||
| -f ./proxy/Dockerfile ./proxy \ | ||
| --push | ||
| - name: get EC2 Instance ID | ||
| id: get-instance | ||
| run: | | ||
| INSTANCE_ID=$(aws ec2 describe-instances \ | ||
| --filters "Name=tag:Name,Values=${{ secrets.EC2_INSTANCE_NAME }}" \ | ||
| "Name=instance-state-name,Values=running" \ | ||
| --query "Reservations[0].Instances[0].InstanceId" \ | ||
| --output text) | ||
| echo "instance_id=$INSTANCE_ID" >> $GITHUB_OUTPUT | ||
| - name: Deploy via SSM | ||
| id: ssm-deploy | ||
| run: | | ||
| COMMAND_ID=$(aws ssm send-command \ | ||
| --instance-ids "${{ steps.get-instance.outputs.instance_id }}" \ | ||
| --document-name "AWS-RunShellScript" \ | ||
| --parameters 'commands=[ | ||
| "aws ecr get-login-password --region ${{ secrets.AWS_REGION }} | sudo docker login --username AWS --password-stdin ${{ secrets.WEB_ECR_IMAGE_URI }}", | ||
| "sudo docker pull ${{ secrets.WEB_ECR_IMAGE_URI }}:latest", | ||
| "aws ecr get-login-password --region ${{ secrets.AWS_REGION }} | sudo docker login --username AWS --password-stdin ${{ secrets.PROXY_ECR_IMAGE_URI }}", | ||
| "sudo docker pull ${{ secrets.PROXY_ECR_IMAGE_URI }}:latest", | ||
| "cd /TEKDB", | ||
| "sudo docker compose down", | ||
| "docker compose --env-file docker/.env.prod -f docker/docker-compose.prod.yaml up -d", | ||
| "sleep 5", | ||
| "docker ps --filter name=web --format \"{{.Status}}\"" | ||
| ]' \ | ||
| --timeout-seconds 120 \ | ||
| --comment "Deploy ${{ github.sha }}" \ | ||
| --query "Command.CommandId" \ | ||
| --output text) | ||
| echo "command_id=$COMMAND_ID" >> $GITHUB_OUTPUT | ||
| - name: Wait for deployment to complete | ||
| run: | | ||
| aws ssm wait command-executed \ | ||
| --command-id ${{ steps.ssm-deploy.outputs.command_id }} \ | ||
| --instance-id ${{ steps.get-instance.outputs.instance_id }} | ||
| - name: Verify deployment result | ||
| run: | | ||
| RESULT=$(aws ssm get-command-invocation \ | ||
| --command-id ${{ steps.ssm-deploy.outputs.command_id }} \ | ||
| --instance-id ${{ steps.get-instance.outputs.instance_id }} \ | ||
| --query "{Status:Status,Output:StandardOutputContent,Error:StandardErrorContent}" \ | ||
| --output json) | ||
| echo "$RESULT" | jq . | ||
| STATUS=$(echo "$RESULT" | jq -r '.Status') | ||
| if [ "$STATUS" != "Success" ]; then | ||
| echo "::error::Deployment failed with status: $STATUS" | ||
| exit 1 | ||
| fi | ||
| echo "Deployment succeeded." | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -42,5 +42,3 @@ ENV DJANGO_SETTINGS_MODULE=TEKDB.settings | |||||
|
|
||||||
| ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] | ||||||
|
|
||||||
|
||||||
| CMD ["dev"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| services: | ||
| db: | ||
| extends: | ||
| file: common.yaml | ||
| service: db | ||
|
|
||
| web: | ||
| extends: | ||
| file: common.yaml | ||
| service: web | ||
| command: ["prod-local"] | ||
| env_file: | ||
| - .env.dev | ||
| ports: [] | ||
| volumes: | ||
| - static_volume:/usr/src/app/static | ||
| - media_volume:/usr/src/app/media | ||
| proxy: | ||
| build: | ||
| context: ../proxy/ | ||
| dockerfile: ../proxy/Dockerfile | ||
| restart: unless-stopped | ||
| depends_on: | ||
| - web | ||
| ports: | ||
| - "8080:8080" | ||
| volumes: | ||
| - static_volume:/vol/static/static:ro | ||
| - media_volume:/vol/static/media:ro | ||
|
|
||
| volumes: | ||
| tekdb_db_data: | ||
| static_volume: | ||
| media_volume: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,46 +1,33 @@ | ||
| services: | ||
| db: | ||
| image: postgis/postgis:15-3.4 | ||
| restart: always | ||
| platform: linux/amd64 | ||
| environment: | ||
| POSTGRES_DB: ${SQL_DATABASE} | ||
| POSTGRES_USER: ${SQL_USER} | ||
| POSTGRES_PASSWORD: ${SQL_PASSWORD} | ||
| volumes: | ||
| - tekdb_db_data:/var/lib/postgresql/data | ||
| ports: | ||
| - "5432:5432" | ||
| healthcheck: | ||
| test: ["CMD-SHELL", "pg_isready -U ${SQL_USER} -d ${SQL_DATABASE} -h localhost -p ${SQL_PORT}"] | ||
| interval: 10s | ||
| timeout: 5s | ||
| retries: 5 | ||
| extends: | ||
| file: common.yaml | ||
| service: db | ||
|
|
||
| web: | ||
| build: | ||
| context: ../TEKDB/ | ||
| dockerfile: ../TEKDB/Dockerfile | ||
| extends: | ||
| file: common.yaml | ||
| service: web | ||
| image: ${ITKDB_ECR_PATH}:latest | ||
|
||
| command: ["prod"] | ||
| env_file: | ||
| - .env.prod | ||
|
Comment on lines
+13
to
+14
|
||
| ports: [] | ||
| volumes: | ||
| - static_volume:/usr/src/app/static | ||
| - media_volume:/usr/src/app/media | ||
| proxy: | ||
| image: ${ITKDB_PROXY_ECR_PATH}:latest | ||
| restart: unless-stopped | ||
| depends_on: | ||
| - db | ||
| env_file: | ||
| - .env.dev | ||
| environment: | ||
| ALLOWED_HOSTS: ${ALLOWED_HOSTS} | ||
| DEBUG: ${DEBUG} | ||
| SQL_ENGINE: ${SQL_ENGINE} | ||
| SQL_HOST: ${SQL_HOST} | ||
| SQL_PORT: ${SQL_PORT} | ||
| SQL_DATABASE: ${SQL_DATABASE} | ||
| SQL_USER: ${SQL_USER} | ||
| SQL_PASSWORD: ${SQL_PASSWORD} | ||
| SECRET_KEY: ${SECRET_KEY} | ||
| - web | ||
| ports: | ||
| - "8000:8000" | ||
| - "80:8080" | ||
| volumes: | ||
| - ../TEKDB:/usr/src/app | ||
| - static_volume:/vol/static/static:ro | ||
| - media_volume:/vol/static/media:ro | ||
|
|
||
| volumes: | ||
| tekdb_db_data: | ||
| static_volume: | ||
| media_volume: | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This workflow only builds and pushes the
webimage to GHCR. However,docker/docker-compose.prod.yamlreferences${ITKDB_PROXY_ECR_PATH}:latestfor the proxy service, andinfra/ecr.tfcreates anaws_ecr_repositoryfor the proxy. There is no step in this workflow (or any other visible workflow) that builds and pushes the proxy image. Without a published proxy image, the production deployment will fail when it attempts to pull it. A separate build step for theproxyimage (context: ./proxy,file: ./proxy/Dockerfile) should be added.