Skip to content

Commit

Permalink
Merge pull request #39 from xtdb/aws-lambda-2
Browse files Browse the repository at this point in the history
Change deployment to via lambda
  • Loading branch information
Akeboshiwind authored May 31, 2024
2 parents c3fedb7 + ad8e323 commit 0a2a358
Show file tree
Hide file tree
Showing 31 changed files with 455 additions and 734 deletions.
96 changes: 43 additions & 53 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,45 +1,20 @@
---
name: Build & Push Docker
name: Build & Deploy

on:
push:
tags:
- 'v*'
branches:
- main

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

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 +29,43 @@ 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: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'yarn'
- name: Install yarn deps
run: yarn install --frozen-lockfile
- 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.

89 changes: 61 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,11 @@

The code behind [XT play](https://play.xtdb.com/), a web tool for exploring the [XTDB database](https://xtdb.com).

## Running

Want to run it locally? Use the docker container:

```sh
docker run -p 3000:8000 --pull=always ghcr.io/xtdb/xt-play
```

Then visit [https://localhost:3000](https://localhost:3000).
(Wait until the first log line appears)
It is deployed on an AWS Lambda but can be run locally as a normal web server for ease of development.

## Deploy

This repo is setup to deploy on *git tags*, specifically `vX.Y.Z` tags.

So deploying is as simple as:
1. Commit & push your changes
2. `git tag vX.Y.Z`
3. `git push --tags`
This repo is setup to deploy on push to `main`, so just merge your PR and go!

## Development

Expand Down Expand Up @@ -54,35 +40,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.

```sh
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>
```

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 \
--capabilities CAPABILITY_IAM \
--stack-name xt-play--lambda-deps \
--template-body "file://$(pwd)/cloudformation/02-lambda-deps.yml"
```

Update:
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 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 CAPABILITY_AUTO_EXPAND \
--stack-name xt-play--lambda \
--template-body "file://$(pwd)/cloudformation/03-lambda.yml" \
--parameters ParameterKey=PlayCodeVersion,ParameterValue=<versionId>
```

Delete
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 delete-stack --stack-name xt-fiddle--github
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
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
- Effect: Allow
Action:
- ecs:UpdateService
- ecs:DescribeServices
- s3:PutObject
- s3:GetObjectVersion
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
Loading

0 comments on commit 0a2a358

Please sign in to comment.