Created
March 11, 2023 01:19
-
-
Save matthewdowney/eb5ae210627e16a6794f6a408e42cc11 to your computer and use it in GitHub Desktop.
Using the AWS CDK from Clojure
This file contains 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
(ns deploy | |
(:require [clojure.java.io :as io]) | |
(:import (software.amazon.awscdk App CfnOutput$Builder Stack) | |
(software.amazon.awscdk.services.apigatewayv2.alpha AddRoutesOptions HttpApi$Builder HttpMethod) | |
(software.amazon.awscdk.services.apigatewayv2.authorizers.alpha HttpIamAuthorizer) | |
(software.amazon.awscdk.services.apigatewayv2.integrations.alpha HttpAlbIntegration) | |
(software.amazon.awscdk.services.ec2 Vpc$Builder) | |
(software.amazon.awscdk.services.ecs Cluster$Builder ContainerImage) | |
(software.amazon.awscdk.services.ecs.patterns ApplicationLoadBalancedFargateService$Builder ApplicationLoadBalancedTaskImageOptions) | |
(software.amazon.awscdk.services.iam AnyPrincipal) | |
(software.amazon.awscdk.services.secretsmanager Secret))) | |
;; A CDK 'app' is the root of a tree of CDK 'constructs', which can be | |
;; CloudFormation stacks or (trees of) AWS resources. | |
;; https://docs.aws.amazon.com/cdk/v2/guide/constructs.html#constructs_tree | |
(def app (App.)) | |
;; The CloudFormation stack containing the resources. Stateful resources could | |
;; be separated out into a different stack, to better control possible | |
;; operations that would destroy existing state (e.g. in a db). | |
;; https://docs.aws.amazon.com/cdk/v2/guide/best-practices.html#best-practices-apps-separate | |
(def stack (Stack. app "AccountingStack")) | |
;;; The resources themselves | |
(def vpc (-> (Vpc$Builder/create stack "vpc") (.maxAzs 3) (.natGateways 1) .build)) | |
;; ECS cluster (used by fargate) | |
(def ecs-cluster | |
(-> (Cluster$Builder/create stack "ecs-cluster") (.vpc vpc) .build)) | |
;; The API keys that the server needs | |
(def api-conf (read-string (slurp (io/resource "conf.edn")))) | |
(defn ecs-secret [{:keys [aws-secret]}] | |
(software.amazon.awscdk.services.ecs.Secret/fromSecretsManager | |
(Secret/fromSecretNameV2 stack aws-secret aws-secret))) | |
;; The code under ./server, as a Fargate service. | |
(def fargate-service | |
(let [docker-image (-> (ApplicationLoadBalancedTaskImageOptions/builder) | |
(.image (ContainerImage/fromAsset "server")) | |
(.secrets (update-vals api-conf ecs-secret)) | |
(.enableLogging true) | |
.build)] | |
(-> (ApplicationLoadBalancedFargateService$Builder/create stack "fargate-service") | |
(.cluster ecs-cluster) | |
(.taskImageOptions docker-image) | |
(.desiredCount 1) | |
(.cpu 256) | |
(.memoryLimitMiB 1024) | |
(.publicLoadBalancer false) | |
.build))) | |
;;; The API Gateway | |
(def api-endpoint | |
(-> (HttpApi$Builder/create stack "HttpProxyPrivateAPI") | |
(.defaultAuthorizer (HttpIamAuthorizer.)) | |
.build)) | |
(def default-route | |
(-> (AddRoutesOptions/builder) | |
(.integration (HttpAlbIntegration. "DefaultIntegration" (.getListener fargate-service))) | |
(.path "/{proxy+}") | |
(.methods [(HttpMethod/ANY)]) | |
.build)) | |
;; Add the route to the API and grant access to any IAM users in this account | |
(let [route (first (.addRoutes api-endpoint default-route))] | |
(.grantInvoke route (AnyPrincipal.))) | |
;; Add the URL to the outputs | |
(-> (CfnOutput$Builder/create stack "apiGatewayURL") | |
(.value (.getUrl api-endpoint)) | |
(.description "The API gateway URL.") | |
(.exportName "apiGatewayURL") | |
.build) | |
(defn synth [& args] | |
(println "Synthesized to:" (.getDirectory (.synth app))) | |
(.getDirectory (.synth app))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment