Skip to content

Commit

Permalink
feat: change deployment to via fiddle
Browse files Browse the repository at this point in the history
  • Loading branch information
Akeboshiwind committed May 31, 2024
1 parent c3fedb7 commit fac513d
Show file tree
Hide file tree
Showing 31 changed files with 443 additions and 718 deletions.
90 changes: 35 additions & 55 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,45 +1,17 @@
---
name: Build & Push Docker
name: Build & Deploy

on:
push:
tags:
- 'v*'
on: push
# on:
# push:
# tags:
# - 'v*'

env:
AWS_REGION: eu-west-1
GH_REGISTRY: ghcr.io

jobs:
build-and-push-github:
runs-on: ubuntu-latest
if: github.repository == 'xtdb/xt-fiddle'
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.GH_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ${{ env.GH_REGISTRY }}/${{ github.repository }}
- name: Build and push Docker image
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

build-and-push-ecr_and_deploy-cloudformation:
build-and-deploy:
runs-on: ubuntu-latest
if: github.repository == 'xtdb/xt-fiddle'
permissions:
Expand All @@ -54,28 +26,36 @@ jobs:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
- name: Prepare java
uses: actions/setup-java@v4.2.1
with:
images: ${{ steps.login-ecr.outputs.registry }}/xt-fiddle
- name: Build and push Docker image
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
distribution: 'temurin'
java-version: '21'
- name: Setup Clojure
uses: DeLaGuardo/setup-clojure@12.5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

- name: Get tag
id: vars
run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
cli: 1.11.3.1463
# - name: Cache clojure dependencies
# uses: actions/cache@v3
# with:
# path: |
# ~/.m2/repository
# ~/.gitlibs
# ~/.deps.clj
# key: cljdeps-${{ hashFiles('deps.edn') }}
# # key: cljdeps-${{ hashFiles('deps.edn', 'bb.edn') }}
# restore-keys: cljdeps-
- name: Build jar
run: clojure -T:build jar
- name: upload to s3
id: upload
run: |
mv target/lib-*.jar xt-play.jar
version=$(aws s3api put-object --body xt-play.jar --bucket xt-play-lambda-code --key xt-play.jar --output text --query VersionId)
echo "version=${version}" >> $GITHUB_OUTPUT
- name: Deploy to AWS CloudFormation
uses: aws-actions/aws-cloudformation-github-deploy@v1
with:
name: 'xt-fiddle--service'
template: cloudformation/service.yml
parameter-overrides: "DockerTag=${{ steps.vars.outputs.tag }}"
name: 'xt-play--lambda'
template: cloudformation/03-lambda.yml
parameter-overrides: "PlayCodeVersion=${{ steps.upload.outputs.version }}"
32 changes: 0 additions & 32 deletions Dockerfile

This file was deleted.

71 changes: 59 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,35 +54,82 @@ You should than be able to browse a dev build at [http://localhost:8000](http://

## Infrastructure

Infrastructure is spread across three files:
Infrastructure is spread across five(!) files, all in the `cloudformation` folder:

| File | Description |
| --- | --- |
| cloudformation/deploy.yml | Contains most of the infra |
| cloudformation/service.yml | Just the bits that the github actions need to deploy |
| cloudformation/github-keys.yml | Contains the user used by github to deploy |
| `00-github-keys.yml` | Contains the user used by github to deploy |
| `01-certificate.yml` | Creates the certificate used by CloudFront (must be deployed in `us-east-1`) |
| `02-lambda-deps.yml` | Contains the things the lambda needs to deploy (an s3 bucket and role |
| `03-lambda.yml` | The lambda itself, in a separate file so github can deploy just that |
| `04-domain.yml` | The stuff needed to address the lambda via a static url |

These are glued together by liberal use of ssm parameters and [dynamic references](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html).

On initial deployment they *must* be deployed in the above order.
On initial deployment they *must* be deployed in the below order.

<details>

<summary>Some example commands</summary>
<summary>Initial creation</summary>

> [!NOTE]
> Wait for each step to finish deploying before deploying the next stage
```sh
aws cloudformation create-stack \
--capabilities CAPABILITY_IAM \
--stack-name xt-play--github \
--template-body "file://$(pwd)/cloudformation/00-github-keys.yml"
```

Make sure to add the access_key_id and secret_access_key to the github actions secrets.

Create:
```sh
aws cloudformation create-stack --capabilities CAPABILITY_IAM --stack-name xt-fiddle--github --template-body "file://$(pwd)/cloudformation/github-keys.yml"
aws cloudformation create-stack \
--region us-east-1 \
--capabilities CAPABILITY_IAM \
--stack-name xt-play--certificate \
--template-body "file://$(pwd)/cloudformation/01-certificate.yml" \
--parameters ParameterKey=HostedZoneId,ParameterValue=<hostedZoneId> \
ParameterKey=HostedZoneName,ParameterValue=<hostedZoneName>
```

Update:
```sh
aws cloudformation update-stack --capabilities CAPABILITY_IAM --stack-name xt-fiddle--github --template-body "file://$(pwd)/cloudformation/github-keys.yml"
aws cloudformation create-stack \
--capabilities CAPABILITY_IAM \
--stack-name xt-play--lambda-deps \
--template-body "file://$(pwd)/cloudformation/02-lambda-deps.yml"
```

Delete
Before running this next step, upload the code to the freshly created s3 bucket.
Look in `03-lambda.yml` for the location.

(Updates to this will mainly be done by github)
```sh
aws cloudformation delete-stack --stack-name xt-fiddle--github
aws cloudformation create-stack \
--capabilities CAPABILITY_IAM CAPABILITY_AUTO_EXPAND \
--stack-name xt-play--lambda \
--template-body "file://$(pwd)/cloudformation/03-lambda.yml" \
--parameters ParameterKey=PlayCodeVersion,ParameterValue=<versionId>
```

The `certificateArn` here is from 01-certificate.yml, it can't be an ssm parameter due to being in a different region :/
```sh
aws cloudformation create-stack \
--capabilities CAPABILITY_IAM \
--stack-name xt-play--domain \
--template-body "file://$(pwd)/cloudformation/04-domain.yml" \
--parameters ParameterKey=HostedZoneId,ParameterValue=<hostedZoneId> \
ParameterKey=HostedZoneName,ParameterValue=<hostedZoneName> \
ParameterKey=CertificateArn,ParameterValue=<certificateArn>
```

> [!NOTE]
> To run an update just swap out `create-stack` for `update-stack`
>
> To delete a stack either use the AWS Console or run:
> ```sh
> aws cloudformation delete-stack --stack-name <stack-name>
> ```
</details>
23 changes: 20 additions & 3 deletions build.clj
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,34 @@
[_]
(b/delete {:path "target"}))

(defn compile-cljs []
(let [{:keys [exit]} (b/process {:command-args ["npx" "shadow-cljs" "release" "app"]})]
(when-not (= 0 exit)
(throw (ex-info "Failed to compile cljs" {:exit exit})))))

(defn jar [_]
(b/copy-dir {:src-dirs ["src" "resources"]
(compile-cljs)
(b/copy-dir {:src-dirs ["src/clj" "resources"]
:target-dir class-dir})
; For xt-version
(b/copy-file {:src "deps.edn"
:target (str class-dir "/deps.edn")})
(b/compile-clj {:basis basis
:src-dirs ["src"]
:src-dirs ["src/clj"]
:class-dir class-dir
:bindings {#'clojure.core/*assert* false}})
(b/uber {:class-dir class-dir
:uber-file jar-file
:main main
:basis basis}))
:basis basis
:conflict-handlers
{"org/apache/arrow/vector/.*" :overwrite
; Defaults
"^data_readers.clj[c]?$" :data-readers
"^META-INF/services/.*" :append
"(?i)^(META-INF/)?(COPYRIGHT|NOTICE|LICENSE)(\\.(txt|md))?$" :append-dedupe
:default :ignore}}))


(comment
(clean nil)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
# This file creates a keys for github to be able to deploy 03-lambda.yml
---
AWSTemplateFormatVersion: '2010-09-09'

Resources:
# >> Github deploy IAM Role

GithubDeployUser:
Type: 'AWS::IAM::User'
Properties:
Policies:
- PolicyName: ecr-allow-push
- PolicyName: lambda
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- ecr:CompleteLayerUpload
- ecr:GetAuthorizationToken
- ecr:UploadLayerPart
- ecr:InitiateLayerUpload
- ecr:BatchCheckLayerAvailability
- ecr:PutImage
- ecr:BatchGetImage
Resource: "*"
- lambda:*
Resource: !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:*"
- PolicyName: ssm-parameter-get
PolicyDocument:
Version: '2012-10-17'
Expand All @@ -31,31 +24,18 @@ Resources:
- ssm:Describe*
- ssm:Get*
- ssm:List*
Resource: !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/xt-fiddle_*"
- PolicyName: task-definition-update
Resource: !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/xt-play_*"
- PolicyName: s3-upload
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: RegisterTaskDefinition
Effect: Allow
Action:
- ecs:RegisterTaskDefinition
- ecs:DeregisterTaskDefinition
Resource: "*"
- Sid: PassRolesInTaskDefinition
Effect: Allow
Action:
- iam:PassRole
Resource:
- '{{resolve:ssm:xt-fiddle_task-role-arn}}'
- '{{resolve:ssm:xt-fiddle_task-execution-role-arn}}'
- Sid: DeployService
Effect: Allow
Action:
- ecs:UpdateService
- ecs:DescribeServices
- s3:PutObject
Resource:
- '{{resolve:ssm:xt-fiddle_ecs-service-arn}}'
- arn:aws:s3:::xt-play-lambda-code
- arn:aws:s3:::xt-play-lambda-code/*
# https://github.com/aws-actions/aws-cloudformation-github-deploy?tab=readme-ov-file#permissions
- PolicyName: cloudformation-deploy
PolicyDocument:
Expand Down
34 changes: 34 additions & 0 deletions cloudformation/01-certificate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# This file creates a certificate for CloudFront to use
# It is in a separate file because:
# - CloudFront requires it be created in `us-east-1`
# - Cloudformation only allows deploying resources to one region at a time
---
# NOTE: Must be created in `us-east-1` because that's a requirement for CloudFront
AWSTemplateFormatVersion: '2010-09-09'

Parameters:
HostedZoneId:
Type: 'String'
Description: 'The zone id for the hosted zone'
HostedZoneName:
Type: 'String'
Description: 'The zone name for the hosted zone'

Resources:
Certificate:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Sub
- '*.${Domain}'
- Domain: !Ref HostedZoneName
ValidationMethod: 'DNS'

DomainValidationOptions:
- DomainName: !Sub
- '*.${Domain}'
- Domain: !Ref HostedZoneName
HostedZoneId: !Ref HostedZoneId

Outputs:
CertificateArn:
Value: !Ref Certificate
Loading

0 comments on commit fac513d

Please sign in to comment.