├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── build ├── hello-world │ ├── Cargo.toml │ ├── Dockerfile │ └── src │ │ └── main.rs └── microservice-demo │ └── Dockerfile ├── kubernetes ├── deployment-microservice.yaml ├── deployment-spin.yaml ├── deployment-wasmedge.yaml └── runtimeclass.yaml ├── packer ├── al2023_amd64.pkrvars.hcl ├── al2023_arm64.pkrvars.hcl ├── amazon-eks-al2023.pkr.hcl ├── plugins.pkr.hcl ├── scripts │ ├── cleanup.sh │ └── wasm-runtimes.sh ├── templates │ ├── containerd-config.toml │ ├── nodeadm-run.service │ └── wasm-init.sh └── variables.pkr.hcl └── terraform ├── eks.tf ├── providers.tf └── templates └── user-data.tpl /.gitignore: -------------------------------------------------------------------------------- 1 | **/.terraform/**/* 2 | **/.terraform* 3 | .terraform/**/* 4 | terraform.* 5 | **/*.pem -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT No Attribution 2 | 3 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 13 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 14 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 15 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 16 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Run WebAssembly workloads on Amazon EKS 2 | 3 | This repository contains code for building custom Amazon EKS AMIs using [HashiCorp Packer](https://www.packer.io/). 4 | The AMIs include necessary binaries and configurations to enable you to run WebAssembly workloads in an EKS cluster and are based on Amazon Linux 2023. The runtimes used in the AMIs are [Spin](https://github.com/fermyon/spin) and [WasmEdge](https://github.com/WasmEdge/WasmEdge). The respective containerd-shims are used for both runtimes. 5 | Deploying the cluster is done using [Hashicorp Terraform](https://www.terraform.io/). 6 | After the cluster is created, RuntimeClasses and example workloads are deployed to the cluster. 7 | 8 | > **Note** 9 | > The code in this repository provides you with a sample to demonstrate how to run WebAssembly workloads on Amazon EKS. 10 | > It does not provide you with a production ready EKS cluster or setup in general. 11 | > To run a production ready EKS cluster, [please adhere to the best-practices AWS has defined](https://aws.github.io/aws-eks-best-practices/). 12 | > In order to make this experience as easy as possible for you, the Kubernetes API of this sample will be reachable from the public internet. 13 | > This is not recommended in production. 14 | 15 | --- 16 | 17 | ## 🔢 Pre-requisites 18 | 19 | You must have the following tools installed on your system: 20 | * AWS CLI (version 2.15.0 or later) 21 | * [Installing AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html#getting-started-install-instructions) 22 | * Packer (version 1.10.0 or later) 23 | * [Installing Packer](https://developer.hashicorp.com/packer/tutorials/docker-get-started/get-started-install-cli) 24 | * Terraform (version 1.7.0 or later) 25 | * [Installing Terraform](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli) 26 | * Kubectl (version 1.29.x) 27 | * [Installing Kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) 28 | * Finch (needed if you want to build the example for WasmEdge) 29 | * [Installing Finch](https://runfinch.com/docs/getting-started/installation/) 30 | * Cloning the repo to your environment 31 | 32 | The easiest way to authenticate Packer and Terraform is [through setting up authentication in the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-authentication.html). Please keep in mind that you will need many permissions to setup this environment. It is assumed that the credentials you use have administrator permissions. 33 | 34 | To test if your AWS CLI works and you are authenticated, run this command: 35 | ``` 36 | aws sts get-caller-identity --output json 37 | ```` 38 | 39 | The output should look like this: 40 | ``` 41 | { 42 | "UserId": "UUID123123:your_user", 43 | "Account": "111122223333", 44 | "Arn": "arn:aws:sts::111122223333:assumed-role/some-role/your_user" 45 | } 46 | ``` 47 | Take note of your account-id, as you will need it later. 48 | 49 | > **Note** 50 | > The default instance type to build the AMI and the EKS cluster does not qualify for the AWS free tier. 51 | > You are charged for any instances created when building this AMI and the EKS cluster. 52 | > An EKS cluster in itself does not qualify for the AWS free tier as well. 53 | > You are charged for any EKS cluster you deploy while building this sample. 54 | 55 | ## 👷 Building the AMIs 56 | 57 | You will need to have a default VPC in the region where the AMIs will be created, or provide a subnet ID via the subnet_id variable. The remaining variables are optional and can be modified to suit; either through the `al2023_amd64.pkrvars.hcl` file or by passing via -var 'key=value' on the Packer CLI. See the `variables.pkr.hcl` file for variables that are available for customization. 58 | 59 | Before running the commands to create the AMIs, do this: 60 | 61 | 1. Set the `region` variable inside the `packer/al2023_amd64.pkrvars.hcl` file and in the `packer/al2023_arm64.pkrvars.hcl` file 62 | 63 | To build the AMIs, run the following commands on your CLI from inside the repository: 64 | ``` 65 | cd packer 66 | packer init -upgrade . 67 | packer build -var-file=al2023_amd64.pkrvars.hcl . 68 | packer build -var-file=al2023_arm64.pkrvars.hcl . 69 | ``` 70 | 71 | The builds should take about 10 minutes (depending on the instance you choose). 72 | After finishing, you see output similar to this: 73 | ``` 74 | ==> Builds finished. The artifacts of successful builds are: 75 | --> amazon-eks.amazon-ebs.this: AMIs were created: 76 | your-region: ami-123456789abc 77 | ``` 78 | Note the AMI-IDs somewhere, you are going to need it in the next step. 79 | 80 | ## Building the EKS cluster 81 | To build the EKS cluster, you must first do the following: 82 | 83 | 1. Update the `region` inside the `terraform/providers.tf` file to the same region you have set for Packer inside the `packer/al2023_amd64.pkrvars.hcl` file. 84 | 2. Set the `custom_ami_id_amd64` parameter and the `custom_ami_id_arm64` parameter inside the `terraform/eks.tf` file to the matching AMI-IDs from the output of Packer. 85 | 86 | To build the cluster, run the following commands on your CLI from inside the repository (you must confirm the last command): 87 | ``` 88 | cd terraform 89 | terraform init 90 | terraform plan 91 | terraform apply 92 | ``` 93 | 94 | The output of `terraform apply` tells you what Terraform is currently creating. You can use the AWS console (WebUI) to check the progress for individual items. 95 | The process should take 15-20 minutes to complete on average. 96 | 97 | ## Running an example workload with the Spin runtime 98 | When your cluster has finished creating, run the following command to configure kubectl for access to your cluster: 99 | ``` 100 | aws eks update-kubeconfig --name webassembly-on-eks --region 101 | ``` 102 | 103 | After that, run the following commands to first create RuntimeClasses for both Spin and WasmEdge and then an example workload that uses Spin as the runtime: 104 | ``` 105 | kubectl apply -f kubernetes/runtimeclass.yaml 106 | kubectl apply -f kubernetes/deployment-spin.yaml 107 | ``` 108 | 109 | Check if the pod has started successfully (this may take a few seconds the first time you run it): 110 | ``` 111 | kubectl get pods -n default 112 | ``` 113 | 114 | Now let's see if it works: 115 | ``` 116 | kubectl port-forward service/hello-spin 8080:80 117 | ``` 118 | If you now access `http://localhost:8080/hello` in a browser, you should be seeing a message saying "Hello world from Spin!". 119 | 120 | This means the Spin runtime is working inside your cluster! 121 | 122 | ## Building a hello-world image and running it with the WasmEdge runtime 123 | 124 | For the next example, you are going to build your own image using Finch and then run it in a deployment. 125 | To build and run the image, run these commands: 126 | ``` 127 | cd build/hello-world 128 | export AWS_ACCOUNT_ID= 129 | export AWS_REGION= 130 | finch build --tag wasm-example --platform wasi/wasm . 131 | finch tag wasm-example:latest $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/wasm-example:latest 132 | aws ecr get-login-password --region $AWS_REGION | finch login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com 133 | finch push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/wasm-example:latest 134 | envsubst < ../../kubernetes/deployment-wasmedge.yaml | kubectl apply -f - 135 | ``` 136 | 137 | Check if the pod has started successfully (this may take a few seconds the first time you run it): 138 | ``` 139 | kubectl get pods -n default 140 | ``` 141 | 142 | Now let's see if it works: 143 | ``` 144 | kubectl port-forward service/wasmedge-hello 8081:80 145 | ``` 146 | 147 | If you now access `http://localhost:8081` in a browser, you should be seeing a message saying "Hello world from WasmEdge!". 148 | 149 | This means the WasmEdge runtime is working inside your cluster! 150 | 151 | Let's scale this deployment up: 152 | ``` 153 | kubectl scale deployment wasmedge-hello --replicas 20 154 | # Wait a few seconds for the pods to start 155 | kubectl get pods 156 | ``` 157 | You should now see 20 pods of your deployment running in the cluster. 158 | Notice how you did not do a multi-architecture build for the container image, but only specified `wasi/wasm` as the platform, but your pods run on both ARM64 and AMD64 nodes. 159 | This is what WebAssembly enables you to do! 160 | 161 | Congratulations! You can now run WebAssembly workloads with both the Spin and the WasmEdge runtime on Amazon EKS! 162 | 163 | ## Building a microservice with a MariaDB backend 164 | 165 | For the next example, you are going to build your own image again. This time you are building a small microservice that has a MariaDB backend. 166 | Before you apply the `deployment-microservice.yaml`file, update the DNS_SERVER variable in the `kubernetes/deployment-microservice.yaml`file. 167 | Let's build this example: 168 | ``` 169 | cd build/hello-world 170 | export AWS_ACCOUNT_ID= 171 | export AWS_REGION= 172 | finch build --tag microservice --platform wasi/wasm . 173 | finch tag microservice:latest $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/microservice:latest 174 | aws ecr get-login-password --region $AWS_REGION | finch login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com 175 | finch push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/microservice:latest 176 | # Create the secret for the database 177 | shuf -er -n20 {A..Z} {a..z} {0..9} | tr -d '\n' | kubectl create secret generic db-secret --from-file=password=/dev/stdin 178 | # Get the IP of your Kubernetes DNS-Service and update the DNS_SERVER variable with it 179 | kubectl get svc kube-dns -n kube-system -o jsonpath='{.spec.clusterIP}' 180 | envsubst < ../../kubernetes/deployment-microservice.yaml | kubectl apply -f - 181 | ``` 182 | 183 | Now, let's see if the pods are runnning and query the microservice: 184 | ``` 185 | # See if the pods are running 186 | kubectl get pods 187 | # Forward the port of the service to localhost 188 | kubectl port-forward service/microservice 8082:8080 189 | # Initialize the database 190 | curl http://localhost:8082/init 191 | # Check for orders (the answer should be empty) 192 | curl http://localhost:8082/orders 193 | # Download sample orders and create them in our database 194 | wget https://raw.githubusercontent.com/second-state/microservice-rust-mysql/main/orders.json 195 | curl http://localhost:8082/create_orders -X POST -d @orders.json 196 | # Check for orders again 197 | curl -s http://localhost:8082/orders | jq 198 | ``` 199 | 200 | That concludes this little demo of running a microservice with WebAssembly in EKS and connecting it to another service. 201 | Now have fun building with WebAssembly on EKS! 202 | 203 | ## Cleaning up 204 | To clean up the resources you created, run the following commands from inside the repository (you have to confirm the second command): 205 | ``` 206 | aws ecr batch-delete-image --region $AWS_REGION --repository-name wasm-example --image-ids "$(aws ecr list-images --region $AWS_REGION --repository-name wasm-example --query 'imageIds[*]' --output json)" 207 | aws ecr batch-delete-image --region $AWS_REGION --repository-name microservice --image-ids "$(aws ecr list-images --region $AWS_REGION --repository-name microservice --query 'imageIds[*]' --output json)" 208 | cd terraform 209 | terraform destroy 210 | ``` 211 | 212 | This will take around 15 minutes to complete again. 213 | After that you still have to delete the custom AMIs and their snapshots. For this you run these commands: 214 | ``` 215 | export AMI_ID_AMD64= 216 | export AMI_ID_ARM64= 217 | export AWS_REGION= 218 | Snapshots="$(aws ec2 describe-images --image-ids $AMI_ID_AMD64 --region $AWS_REGION --query 'Images[*].BlockDeviceMappings[*].Ebs.SnapshotId' --output text)" 219 | 220 | aws ec2 deregister-image --image-id $AMI_ID_AMD64 --region $AWS_REGION 221 | 222 | for SNAPSHOT in $Snapshots ; do aws ec2 delete-snapshot --snapshot-id $SNAPSHOT; done 223 | 224 | Snapshots="$(aws ec2 describe-images --image-ids $AMI_ID_ARM64 --region $AWS_REGION --query 'Images[*].BlockDeviceMappings[*].Ebs.SnapshotId' --output text)" 225 | 226 | aws ec2 deregister-image --image-id $AMI_ID_ARM64 --region $AWS_REGION 227 | 228 | for SNAPSHOT in $Snapshots ; do aws ec2 delete-snapshot --snapshot-id $SNAPSHOT --region $AWS_REGION; done 229 | ``` 230 | 231 | ## 🔒 Security 232 | 233 | For security issues or concerns, please do not open an issue or pull request on GitHub. Please report any suspected or confirmed security issues to AWS Security https://aws.amazon.com/security/vulnerability-reporting/ 234 | 235 | ## ⚖️ License Summary 236 | 237 | This sample code is made available under a modified MIT license. See the LICENSE file. -------------------------------------------------------------------------------- /build/hello-world/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "server" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [[bin]] 7 | name = "server" 8 | path = "src/main.rs" 9 | 10 | [dependencies] 11 | hyper_wasi = { version = "0.15", features = ["full"] } 12 | tokio_wasi = { version = "1", features = ["rt", "macros", "net", "time", "io-util"] } -------------------------------------------------------------------------------- /build/hello-world/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | FROM --platform=$BUILDPLATFORM rust:1.79.0-slim AS build 4 | WORKDIR /src 5 | COPY Cargo.toml . 6 | COPY src ./src 7 | RUN <) -> Result, hyper::Error> { 6 | match (req.method(), req.uri().path()) { 7 | (&Method::GET, "/") => Ok(Response::new(Body::from("Hello world from WasmEdge"))), 8 | _ => Ok(Response::default()), 9 | } 10 | } 11 | 12 | #[tokio::main(flavor = "current_thread")] 13 | async fn main() -> Result<(), Box> { 14 | let addr = SocketAddr::from(([0, 0, 0, 0], 8080)); 15 | 16 | let make_service = make_service_fn(|_conn| async { 17 | Ok::<_, hyper::Error>(service_fn(handle_request)) 18 | }); 19 | 20 | let server = Server::bind(&addr).serve(make_service); 21 | 22 | println!("Listening on http://{}", addr); 23 | 24 | if let Err(e) = server.await { 25 | eprintln!("Server error: {}", e); 26 | } 27 | 28 | Ok(()) 29 | } -------------------------------------------------------------------------------- /build/microservice-demo/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | 3 | FROM --platform=$BUILDPLATFORM rust:1.79.0-slim AS build 4 | WORKDIR /src 5 | RUN <:53 71 | resources: 72 | limits: 73 | memory: 128Mi 74 | requests: 75 | cpu: 100m 76 | memory: 128Mi 77 | --- 78 | apiVersion: v1 79 | kind: Service 80 | metadata: 81 | name: microservice 82 | spec: 83 | ports: 84 | - protocol: TCP 85 | port: 8080 86 | targetPort: 8080 87 | selector: 88 | app: microservice -------------------------------------------------------------------------------- /kubernetes/deployment-spin.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: hello-spin 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: hello-spin 11 | template: 12 | metadata: 13 | labels: 14 | app: hello-spin 15 | spec: 16 | runtimeClassName: spin 17 | containers: 18 | - name: hello-spin 19 | # This would be a best practice. However, the example image wants to run as root, so this is not used here. 20 | #securityContext: 21 | # runAsNonRoot: true 22 | # readOnlyRootFilesystem: true 23 | # allowPrivilegeEscalation: false 24 | # seccompProfile: 25 | # type: RuntimeDefault 26 | image: ghcr.io/deislabs/containerd-wasm-shims/examples/spin-rust-hello@sha256:da2c07d3bf122b485a13518783cacd95104a9dab0a0f08c102a8089c56cdf40c 27 | command: ["/"] 28 | resources: 29 | limits: 30 | memory: 128Mi 31 | requests: 32 | cpu: 100m 33 | memory: 128Mi 34 | --- 35 | apiVersion: v1 36 | kind: Service 37 | metadata: 38 | name: hello-spin 39 | spec: 40 | ports: 41 | - protocol: TCP 42 | port: 80 43 | targetPort: 80 44 | selector: 45 | app: hello-spin 46 | -------------------------------------------------------------------------------- /kubernetes/deployment-wasmedge.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: wasmedge-hello 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: wasmedge-hello 11 | template: 12 | metadata: 13 | labels: 14 | app: wasmedge-hello 15 | spec: 16 | runtimeClassName: wasmedge 17 | containers: 18 | - name: wasmedge-hello 19 | # This would be a best practice. However, the example image wants to run as root, so this is not used here. 20 | #securityContext: 21 | # runAsNonRoot: true 22 | # readOnlyRootFilesystem: true 23 | # allowPrivilegeEscalation: false 24 | # seccompProfile: 25 | # type: RuntimeDefault 26 | # Example: image: 111122223333.dkr.ecr.aa-example-1.amazonaws.com/wasm-example:latest 27 | image: $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/wasm-example:latest 28 | resources: 29 | limits: 30 | memory: 128Mi 31 | requests: 32 | cpu: 100m 33 | memory: 128Mi 34 | --- 35 | apiVersion: v1 36 | kind: Service 37 | metadata: 38 | name: wasmedge-hello 39 | spec: 40 | ports: 41 | - protocol: TCP 42 | port: 80 43 | targetPort: 8080 44 | selector: 45 | app: wasmedge-hello 46 | -------------------------------------------------------------------------------- /kubernetes/runtimeclass.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: node.k8s.io/v1 3 | kind: RuntimeClass 4 | metadata: 5 | name: wasmedge 6 | handler: wasmedge 7 | --- 8 | apiVersion: node.k8s.io/v1 9 | kind: RuntimeClass 10 | metadata: 11 | name: spin 12 | handler: spin 13 | -------------------------------------------------------------------------------- /packer/al2023_amd64.pkrvars.hcl: -------------------------------------------------------------------------------- 1 | ######## set this to your region ######## 2 | region = "aa-example-1" 3 | ######################################### 4 | eks_version = "1.31" 5 | instance_type = "c6i.large" 6 | ami_description = "Amazon EKS Kubernetes AMI based on AmazonLinux2023 OS" 7 | 8 | ami_block_device_mappings = [ 9 | { 10 | device_name = "/dev/xvda" 11 | volume_size = 40 12 | }, 13 | ] 14 | 15 | launch_block_device_mappings = [ 16 | { 17 | device_name = "/dev/xvda" 18 | volume_size = 40 19 | } 20 | ] 21 | 22 | shell_provisioner1 = { 23 | expect_disconnect = true 24 | scripts = [ 25 | "scripts/wasm-runtimes.sh", 26 | "scripts/cleanup.sh" 27 | ] 28 | environment_vars = [ 29 | "wasmedge_shim_download_url=https://github.com/containerd/runwasi/releases/download/containerd-shim-wasmedge%2Fv0.4.0/containerd-shim-wasmedge-x86_64.tar.gz", 30 | "spin_shim_download_url=https://github.com/spinkube/containerd-shim-spin/releases/download/v0.15.1/containerd-shim-spin-v2-linux-x86_64.tar.gz" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /packer/al2023_arm64.pkrvars.hcl: -------------------------------------------------------------------------------- 1 | ######## set this to your region ######## 2 | region = "aa-example-1" 3 | ######################################### 4 | eks_version = "1.31" 5 | instance_type = "c6g.large" 6 | architecture = "arm64" 7 | ami_description = "Amazon EKS Kubernetes AMI based on AmazonLinux2023 OS" 8 | 9 | ami_block_device_mappings = [ 10 | { 11 | device_name = "/dev/xvda" 12 | volume_size = 40 13 | }, 14 | ] 15 | 16 | launch_block_device_mappings = [ 17 | { 18 | device_name = "/dev/xvda" 19 | volume_size = 40 20 | } 21 | ] 22 | 23 | shell_provisioner1 = { 24 | expect_disconnect = true 25 | scripts = [ 26 | "scripts/wasm-runtimes.sh", 27 | "scripts/cleanup.sh" 28 | ] 29 | environment_vars = [ 30 | "wasmedge_shim_download_url=https://github.com/containerd/runwasi/releases/download/containerd-shim-wasmedge%2Fv0.4.0/containerd-shim-wasmedge-aarch64.tar.gz", 31 | "spin_shim_download_url=https://github.com/spinkube/containerd-shim-spin/releases/download/v0.15.1/containerd-shim-spin-v2-linux-x86_64.tar.gz" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /packer/amazon-eks-al2023.pkr.hcl: -------------------------------------------------------------------------------- 1 | locals { 2 | timestamp = regex_replace(timestamp(), "[- TZ:]", "") 3 | 4 | ami_name = "${var.ami_name_prefix}-${var.eks_version}-${local.timestamp}" 5 | 6 | tags = { 7 | SourceAMI = "{{ .SourceAMI }}" 8 | Name = local.ami_name 9 | } 10 | } 11 | 12 | data "amazon-parameterstore" "this" { 13 | name = "/aws/service/eks/optimized-ami/${var.eks_version}/${var.ami_type}/${var.architecture}/standard/recommended/image_id" 14 | region = var.region 15 | } 16 | 17 | ################################################################################ 18 | # EBS Source 19 | ################################################################################ 20 | 21 | source "amazon-ebs" "this" { 22 | 23 | # AMI Configuration 24 | dynamic "ami_block_device_mappings" { 25 | for_each = var.ami_block_device_mappings 26 | 27 | content { 28 | delete_on_termination = try(ami_block_device_mappings.value.delete_on_termination, true) 29 | device_name = try(ami_block_device_mappings.value.device_name, null) 30 | encrypted = try(ami_block_device_mappings.value.encrypted, null) 31 | iops = try(ami_block_device_mappings.value.iops, null) 32 | no_device = try(ami_block_device_mappings.value.no_device, null) 33 | snapshot_id = try(ami_block_device_mappings.value.snapshot_id, null) 34 | throughput = try(ami_block_device_mappings.value.throughput, null) 35 | virtual_name = try(ami_block_device_mappings.value.virtual_name, null) 36 | volume_size = try(ami_block_device_mappings.value.volume_size, null) 37 | volume_type = try(ami_block_device_mappings.value.volume_type, "gp3") 38 | kms_key_id = try(ami_block_device_mappings.value.kms_key_id, null) 39 | } 40 | } 41 | 42 | ami_description = var.ami_description 43 | ami_groups = var.ami_groups 44 | ami_name = local.ami_name 45 | ami_org_arns = var.ami_org_arns 46 | ami_ou_arns = var.ami_ou_arns 47 | ami_regions = var.ami_regions 48 | ami_users = var.ami_users 49 | ami_virtualization_type = var.ami_virtualization_type 50 | deprecate_at = var.deprecate_at 51 | ena_support = var.ena_support 52 | encrypt_boot = var.encrypt_boot 53 | force_deregister = var.force_deregister 54 | force_delete_snapshot = var.force_delete_snapshot 55 | imds_support = var.imds_support 56 | kms_key_id = var.kms_key_id 57 | 58 | dynamic "launch_block_device_mappings" { 59 | for_each = length(var.launch_block_device_mappings) > 0 ? var.launch_block_device_mappings : var.ami_block_device_mappings 60 | 61 | content { 62 | delete_on_termination = try(launch_block_device_mappings.value.delete_on_termination, true) 63 | device_name = try(launch_block_device_mappings.value.device_name, null) 64 | encrypted = try(launch_block_device_mappings.value.encrypted, null) 65 | iops = try(launch_block_device_mappings.value.iops, null) 66 | no_device = try(launch_block_device_mappings.value.no_device, null) 67 | snapshot_id = try(launch_block_device_mappings.value.snapshot_id, null) 68 | throughput = try(launch_block_device_mappings.value.throughput, null) 69 | virtual_name = try(launch_block_device_mappings.value.virtual_name, null) 70 | volume_size = try(launch_block_device_mappings.value.volume_size, null) 71 | volume_type = try(launch_block_device_mappings.value.volume_type, "gp3") 72 | } 73 | } 74 | 75 | region_kms_key_ids = var.region_kms_key_ids 76 | run_volume_tags = var.run_volume_tags 77 | skip_region_validation = var.skip_region_validation 78 | skip_save_build_region = var.skip_save_build_region 79 | sriov_support = var.sriov_support 80 | snapshot_groups = var.snapshot_groups 81 | snapshot_tags = var.snapshot_tags 82 | snapshot_users = var.snapshot_users 83 | tags = merge(local.tags, var.tags) 84 | 85 | # Access Configuration 86 | access_key = var.access_key 87 | 88 | dynamic "assume_role" { 89 | for_each = length(var.assume_role) > 0 ? [var.assume_role] : [] 90 | 91 | content { 92 | duration_seconds = try(assume_role.value.duration_seconds, null) 93 | external_id = try(assume_role.value.external_id, null) 94 | policy = try(assume_role.value.policy, null) 95 | policy_arns = try(assume_role.value.policy_arns, null) 96 | role_arn = try(assume_role.value.role_arn, null) 97 | session_name = try(assume_role.value.session_name, null) 98 | tag = try(assume_role.value.tag, null) 99 | transitive_tag_keys = try(assume_role.value.transitive_tag_keys, null) 100 | } 101 | } 102 | 103 | dynamic "aws_polling" { 104 | for_each = length(var.aws_polling) > 0 ? [var.aws_polling] : [] 105 | 106 | content { 107 | delay_seconds = try(aws_polling.value.delay_seconds, null) 108 | max_attempts = try(aws_polling.value.max_attempts, null) 109 | } 110 | } 111 | 112 | custom_endpoint_ec2 = var.custom_endpoint_ec2 113 | decode_authorization_messages = var.decode_authorization_messages 114 | insecure_skip_tls_verify = var.insecure_skip_tls_verify 115 | max_retries = var.max_retries 116 | mfa_code = var.mfa_code 117 | profile = var.profile 118 | region = var.region 119 | secret_key = var.secret_key 120 | shared_credentials_file = var.shared_credentials_file 121 | skip_credential_validation = var.skip_credential_validation 122 | skip_metadata_api_check = var.skip_metadata_api_check 123 | token = var.token 124 | 125 | # Communicator 126 | communicator = var.communicator 127 | pause_before_connecting = var.pause_before_connecting 128 | ssh_agent_auth = var.ssh_agent_auth 129 | ssh_bastion_agent_auth = var.ssh_bastion_agent_auth 130 | ssh_bastion_certificate_file = var.ssh_bastion_certificate_file 131 | ssh_bastion_host = var.ssh_bastion_host 132 | ssh_bastion_interactive = var.ssh_bastion_interactive 133 | ssh_bastion_password = var.ssh_bastion_password 134 | ssh_bastion_port = var.ssh_bastion_port 135 | ssh_bastion_private_key_file = var.ssh_bastion_private_key_file 136 | ssh_bastion_username = var.ssh_bastion_username 137 | ssh_ciphers = var.ssh_ciphers 138 | ssh_certificate_file = var.ssh_certificate_file 139 | ssh_clear_authorized_keys = var.ssh_clear_authorized_keys 140 | ssh_disable_agent_forwarding = var.ssh_disable_agent_forwarding 141 | ssh_file_transfer_method = var.ssh_file_transfer_method 142 | ssh_handshake_attempts = var.ssh_handshake_attempts 143 | ssh_host = var.ssh_host 144 | ssh_interface = var.ssh_interface # "public_dns" 145 | ssh_keep_alive_interval = var.ssh_keep_alive_interval 146 | ssh_key_exchange_algorithms = var.ssh_key_exchange_algorithms 147 | ssh_keypair_name = var.ssh_keypair_name 148 | ssh_local_tunnels = var.ssh_local_tunnels 149 | ssh_password = var.ssh_password 150 | ssh_port = var.ssh_port 151 | ssh_private_key_file = var.ssh_private_key_file 152 | ssh_proxy_host = var.ssh_proxy_host 153 | ssh_proxy_password = var.ssh_proxy_password 154 | ssh_proxy_port = var.ssh_proxy_port 155 | ssh_proxy_username = var.ssh_proxy_username 156 | ssh_pty = var.ssh_pty 157 | ssh_read_write_timeout = var.ssh_read_write_timeout 158 | ssh_remote_tunnels = var.ssh_remote_tunnels 159 | ssh_timeout = var.ssh_timeout 160 | ssh_username = var.ssh_username 161 | temporary_key_pair_bits = var.temporary_key_pair_bits 162 | temporary_key_pair_type = var.temporary_key_pair_type 163 | 164 | # Run Configuration 165 | associate_public_ip_address = var.associate_public_ip_address 166 | capacity_reservation_preference = var.capacity_reservation_preference 167 | capacity_reservation_group_arn = var.capacity_reservation_group_arn 168 | capacity_reservation_id = var.capacity_reservation_id 169 | disable_stop_instance = var.disable_stop_instance 170 | ebs_optimized = var.ebs_optimized 171 | enable_nitro_enclave = var.enable_nitro_enclave 172 | enable_unlimited_credits = var.enable_unlimited_credits 173 | iam_instance_profile = var.iam_instance_profile 174 | instance_type = var.instance_type 175 | fleet_tags = var.fleet_tags 176 | pause_before_ssm = var.pause_before_ssm 177 | 178 | dynamic "placement" { 179 | for_each = length(var.placement) > 0 ? [var.placement] : [] 180 | 181 | content { 182 | host_resource_group_arn = try(placement.value.host_resource_group_arn, null) 183 | tenancy = try(placement.value.tenancy, null) 184 | } 185 | } 186 | 187 | run_tags = merge(local.tags, var.run_tags) 188 | security_group_ids = var.security_group_ids 189 | 190 | dynamic "security_group_filter" { 191 | for_each = length(var.security_group_filter) > 0 ? var.security_group_filter : [] 192 | 193 | content { 194 | filters = try(security_group_filter.value.filters, null) 195 | } 196 | } 197 | 198 | session_manager_port = var.session_manager_port 199 | shutdown_behavior = var.shutdown_behavior 200 | skip_profile_validation = var.skip_profile_validation 201 | ######################################################################## 202 | ######################################################################## 203 | ######################################################################## 204 | source_ami = data.amazon-parameterstore.this.value 205 | 206 | dynamic "subnet_filter" { 207 | for_each = length(var.subnet_filter) > 0 ? var.subnet_filter : [] 208 | 209 | content { 210 | filters = try(subnet_filter.value.filters, null) 211 | most_free = try(subnet_filter.value.most_free, null) 212 | random = try(subnet_filter.value.random, null) 213 | } 214 | } 215 | 216 | subnet_id = var.subnet_id 217 | temporary_security_group_source_cidrs = var.temporary_security_group_source_cidrs 218 | temporary_security_group_source_public_ip = var.temporary_security_group_source_public_ip 219 | user_data = var.user_data 220 | user_data_file = var.user_data_file 221 | 222 | dynamic "vpc_filter" { 223 | for_each = length(var.vpc_filter) > 0 ? var.vpc_filter : [] 224 | 225 | content { 226 | filters = try(vpc_filter.value.filters, null) 227 | } 228 | } 229 | 230 | vpc_id = var.vpc_id 231 | 232 | dynamic "metadata_options" { 233 | for_each = length(var.metadata_options) > 0 ? [var.metadata_options] : [] 234 | 235 | content { 236 | http_endpoint = try(metadata_options.value.http_endpoint, null) 237 | http_put_response_hop_limit = try(metadata_options.value.http_put_response_hop_limit, null) 238 | http_tokens = try(metadata_options.value.http_tokens, null) 239 | instance_metadata_tags = try(metadata_options.value.instance_metadata_tags, null) 240 | } 241 | } 242 | } 243 | 244 | ################################################################################ 245 | # Build 246 | ################################################################################ 247 | 248 | build { 249 | name = var.ami_name_prefix 250 | sources = ["source.amazon-ebs.this"] 251 | 252 | provisioner "file" { 253 | source = "templates/nodeadm-run.service" 254 | destination = "/home/ec2-user/nodeadm-run.service" 255 | } 256 | 257 | provisioner "file" { 258 | source = "templates/containerd-config.toml" 259 | destination = "/home/ec2-user/containerd-config.toml" 260 | } 261 | 262 | provisioner "file" { 263 | source = "templates/wasm-init.sh" 264 | destination = "/home/ec2-user/wasm-init.sh" 265 | } 266 | 267 | provisioner "shell" { 268 | execute_command = "echo 'packer' | sudo -S sh -c '{{ .Vars }} {{ .Path }}'" 269 | 270 | inline = try(var.shell_provisioner1.inline, null) 271 | script = try(var.shell_provisioner1.script, null) 272 | scripts = try(var.shell_provisioner1.scripts, ["scripts/dummy.sh"]) 273 | 274 | env = try(var.shell_provisioner1.env, null) 275 | environment_vars = try(var.shell_provisioner1.environment_vars, null) 276 | 277 | expect_disconnect = try(var.shell_provisioner1.expect_disconnect, false) 278 | pause_after = try(var.shell_provisioner1.pause_after, "15s") 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /packer/plugins.pkr.hcl: -------------------------------------------------------------------------------- 1 | packer { 2 | required_plugins { 3 | amazon = { 4 | version = ">= 1.3.0" 5 | source = "github.com/hashicorp/amazon" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packer/scripts/cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Clean up yum caches to reduce the image size 4 | sudo yum clean all 5 | sudo rm -rf /var/cache/yum 6 | 7 | # Clean up files to reduce confusion during debug 8 | sudo rm -rf \ 9 | /etc/hostname \ 10 | /etc/machine-id \ 11 | /etc/resolv.conf \ 12 | /etc/ssh/ssh_host* \ 13 | /home/ec2-user/.ssh/authorized_keys \ 14 | /root/.ssh/authorized_keys \ 15 | /var/lib/cloud/data \ 16 | /var/lib/cloud/instance \ 17 | /var/lib/cloud/instances \ 18 | /var/lib/cloud/sem \ 19 | /var/lib/dhclient/* \ 20 | /var/lib/dhcp/dhclient.* \ 21 | /var/lib/yum/history \ 22 | /var/lib/dnf/history* \ 23 | /var/log/cloud-init-output.log \ 24 | /var/log/cloud-init.log \ 25 | /var/log/secure \ 26 | /var/log/wtmp \ 27 | /var/log/messages \ 28 | /var/log/audit/* 29 | 30 | sudo touch /etc/machine-id 31 | -------------------------------------------------------------------------------- /packer/scripts/wasm-runtimes.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o pipefail 4 | set -o nounset 5 | set -o errexit 6 | 7 | # Download the wasm containerd shims 8 | curl -fsSL "${wasmedge_shim_download_url}" | tar -C /bin -xzf - 9 | curl -fsSL "${spin_shim_download_url}" | tar -C /bin -xzf - 10 | 11 | # Set the correct owner and permissions for the shim binary 12 | chown root:root /bin/containerd-shim-wasmedge-v1 13 | chown root:root /bin/containerd-shim-spin-v2 14 | chmod 0750 /home/ec2-user/wasm-init.sh 15 | 16 | # Delete the current service file and move the new one to the systemd directory for the nodeadm-run service 17 | rm -f /etc/systemd/system/nodeadm-run.service 18 | mv /home/ec2-user/nodeadm-run.service /etc/systemd/system/nodeadm-run.service 19 | 20 | # Set the correct owner and permissions for the service file 21 | chown root:root /etc/systemd/system/nodeadm-run.service 22 | chmod 0644 /etc/systemd/system/nodeadm-run.service 23 | 24 | # Reload the systemd daemon to pick up the new service file 25 | systemctl daemon-reload -------------------------------------------------------------------------------- /packer/templates/containerd-config.toml: -------------------------------------------------------------------------------- 1 | [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.wasmedge] 2 | runtime_type = "io.containerd.wasmedge.v1" 3 | [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.wasmedge.options] 4 | BinaryName = "/bin/containerd-shim-wasmedge-v1" 5 | [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.spin] 6 | runtime_type = "io.containerd.spin.v2" 7 | [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.spin.options] 8 | BinaryName = "/bin/containerd-shim-spin-v2" -------------------------------------------------------------------------------- /packer/templates/nodeadm-run.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=EKS Nodeadm Run 3 | Documentation=https://github.com/awslabs/amazon-eks-ami 4 | # start after cloud-init, in order to pickup changes the 5 | # user may have applied via cloud-init scripts 6 | After=nodeadm-config.service cloud-final.service 7 | Requires=nodeadm-config.service 8 | 9 | [Service] 10 | Type=oneshot 11 | ExecStart=/usr/bin/nodeadm init --skip config 12 | ExecStartPost=/home/ec2-user/wasm-init.sh 13 | 14 | [Install] 15 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /packer/templates/wasm-init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Import the needed config for containerd into the already present config file 4 | cat /home/ec2-user/containerd-config.toml >> /etc/containerd/config.toml 5 | 6 | # Restart and enable containerd and kubelet 7 | systemctl restart containerd 8 | systemctl enable containerd 9 | systemctl restart kubelet 10 | systemctl enable kubelet 11 | 12 | # Disable nodeadm services 13 | systemctl disable nodeadm-config.service 14 | systemctl disable nodeadm-run.service -------------------------------------------------------------------------------- /packer/variables.pkr.hcl: -------------------------------------------------------------------------------- 1 | variable "architecture" { 2 | description = "The CPU architecture you want your AMI to use. Set this to x86_64 or arm64" 3 | type = string 4 | # maybe set version and arch as variables to make this more dynamic? 5 | default = "x86_64" 6 | } 7 | 8 | variable "ami_name_prefix" { 9 | description = "The prefix to use when creating the AMI name. i.e. - `--" 10 | type = string 11 | default = "amazon-eks" 12 | } 13 | 14 | variable "eks_version" { 15 | description = "The EKS cluster version associated with the AMI created" 16 | type = string 17 | default = "1.29" 18 | } 19 | 20 | variable "ami_type" { 21 | description = "The type of AMI to create. Valid values are `amazon-linux-2023` or `amazon-linux-2023-arm64`" 22 | type = string 23 | default = "amazon-linux-2023" 24 | } 25 | 26 | ################################################################################ 27 | # EBS Source 28 | ################################################################################ 29 | 30 | variable "ami_block_device_mappings" { 31 | description = "The block device mappings attached when booting a new instance from the AMI created" 32 | type = list(map(string)) 33 | default = [ 34 | { 35 | device_name = "/dev/xvda" 36 | volume_size = 10 37 | volume_type = "gp3" 38 | delete_on_termination = true 39 | }, 40 | ] 41 | } 42 | 43 | variable "ami_description" { 44 | description = "The description to use when creating the AMI" 45 | type = string 46 | default = "Amazon EKS Kubernetes AMI based on AmazonLinux2023 OS" 47 | } 48 | 49 | variable "ami_groups" { 50 | description = "A list of groups that have access to launch the resulting AMI(s). By default no groups have permission to launch the AMI. `all` will make the AMI publicly accessible. AWS currently doesn't accept any value other than `all`" 51 | type = list(string) 52 | default = null 53 | } 54 | 55 | variable "ami_org_arns" { 56 | description = "A list of Amazon Resource Names (ARN) of AWS Organizations that have access to launch the resulting AMI(s). By default no organizations have permission to launch the AMI" 57 | type = list(string) 58 | default = null 59 | } 60 | 61 | variable "ami_ou_arns" { 62 | description = "A list of Amazon Resource Names (ARN) of AWS Organizations organizational units (OU) that have access to launch the resulting AMI(s). By default no organizational units have permission to launch the AMI" 63 | type = list(string) 64 | default = null 65 | } 66 | 67 | variable "ami_regions" { 68 | description = "A list of regions to copy the AMI to. Tags and attributes are copied along with the AMI. AMI copying takes time depending on the size of the AMI, but will generally take many minutes" 69 | type = list(string) 70 | default = null 71 | } 72 | 73 | variable "ami_users" { 74 | description = "A list of account IDs that have access to launch the resulting AMI(s). By default no additional users other than the user creating the AMI has permissions to launch it" 75 | type = list(string) 76 | default = null 77 | } 78 | 79 | variable "ami_virtualization_type" { 80 | description = "The type of virtualization used to create the AMI. Can be one of `hvm` or `paravirtual`" 81 | type = string 82 | default = "hvm" 83 | } 84 | 85 | variable "deprecate_at" { 86 | description = "The date and time to deprecate the AMI, in UTC, in the following format: YYYY-MM-DDTHH:MM:SSZ. If you specify a value for seconds, Amazon EC2 rounds the seconds to the nearest minute" 87 | type = string 88 | default = null 89 | } 90 | 91 | variable "ena_support" { 92 | description = "Enable enhanced networking (ENA but not SriovNetSupport) on HVM-compatible AMIs" 93 | type = bool 94 | default = null 95 | } 96 | 97 | variable "encrypt_boot" { 98 | description = "Whether or not to encrypt the resulting AMI when copying a provisioned instance to an AMI. By default, Packer will keep the encryption setting to what it was in the source image" 99 | type = bool 100 | default = null 101 | } 102 | 103 | variable "force_deregister" { 104 | description = "Force Packer to first deregister an existing AMI if one with the same name already exists. Default `false`" 105 | type = bool 106 | default = null 107 | } 108 | 109 | variable "force_delete_snapshot" { 110 | description = "Force Packer to delete snapshots associated with AMIs, which have been deregistered by force_deregister. Default `false`" 111 | type = bool 112 | default = null 113 | } 114 | 115 | variable "imds_support" { 116 | description = "Enforce version of the Instance Metadata Service on the built AMI. Valid options are `unset` (legacy) and `v2.0`" 117 | type = string 118 | default = "v2.0" 119 | } 120 | 121 | variable "kms_key_id" { 122 | description = "ID, alias or ARN of the KMS key to use for AMI encryption. This only applies to the main `region` -- any regions the AMI gets copied to copied will be encrypted by the default EBS KMS key for that region, unless you set region-specific keys in `region_kms_key_ids`" 123 | type = string 124 | default = null 125 | } 126 | 127 | variable "launch_block_device_mappings" { 128 | description = "The block device mappings to use when creating the AMI. If you add instance store volumes or EBS volumes in addition to the root device volume, the created AMI will contain block device mapping information for those volumes. Amazon creates snapshots of the source instance's root volume and any other EBS volumes described here. When you launch an instance from this new AMI, the instance automatically launches with these additional volumes, and will restore them from snapshots taken from the source instance" 129 | type = list(map(string)) 130 | default = [ 131 | { 132 | device_name = "/dev/xvda" 133 | volume_size = 10 134 | volume_type = "gp3" 135 | delete_on_termination = true 136 | }, 137 | ] 138 | } 139 | 140 | variable "region_kms_key_ids" { 141 | description = "regions to copy the ami to, along with the custom kms key id (alias or arn) to use for encryption for that region. Keys must match the regions provided in `ami_regions`" 142 | type = map(string) 143 | default = null 144 | } 145 | 146 | variable "run_volume_tags" { 147 | description = "Tags to apply to the volumes that are launched to create the AMI. These tags are not applied to the resulting AMI" 148 | type = map(string) 149 | default = null 150 | } 151 | 152 | variable "skip_region_validation" { 153 | description = "Set to `true` if you want to skip validation of the `ami_regions` configuration option. Default `false`" 154 | type = bool 155 | default = null 156 | } 157 | 158 | variable "skip_save_build_region" { 159 | description = "If true, Packer will not check whether an AMI with the ami_name exists in the region it is building in. It will use an intermediary AMI name, which it will not convert to an AMI in the build region. Default `false`" 160 | type = bool 161 | default = null 162 | } 163 | 164 | variable "sriov_support" { 165 | description = "Enable enhanced networking (SriovNetSupport but not ENA) on HVM-compatible AMIs" 166 | type = bool 167 | default = null 168 | } 169 | 170 | variable "snapshot_groups" { 171 | description = "A list of groups that have access to create volumes from the snapshot(s). By default no groups have permission to create volumes from the snapshot(s). all will make the snapshot publicly accessible" 172 | type = list(string) 173 | default = null 174 | } 175 | 176 | variable "snapshot_tags" { 177 | description = "Key/value pair tags to apply to snapshot. They will override AMI tags if already applied to snapshot" 178 | type = map(string) 179 | default = null 180 | } 181 | 182 | variable "snapshot_users" { 183 | description = "A list of account IDs that have access to create volumes from the snapshot(s). By default no additional users other than the user creating the AMI has permissions to create volumes from the backing snapshot(s)" 184 | type = list(string) 185 | default = null 186 | } 187 | 188 | variable "tags" { 189 | description = "Key/value pair tags applied to the AMI" 190 | type = map(string) 191 | default = {} 192 | } 193 | 194 | # Access Configuration 195 | 196 | variable "access_key" { 197 | description = "The access key used to communicate with AWS" 198 | type = string 199 | default = null 200 | } 201 | 202 | variable "assume_role" { 203 | description = "If provided with a role ARN, Packer will attempt to assume this role using the supplied credentials" 204 | type = map(string) 205 | default = {} 206 | } 207 | 208 | variable "aws_polling" { 209 | description = "Polling configuration for the AWS waiter. Configures the waiter for resources creation or actions like attaching volumes or importing image" 210 | type = map(string) 211 | default = {} 212 | } 213 | 214 | variable "custom_endpoint_ec2" { 215 | description = "This option is useful if you use a cloud provider whose API is compatible with aws EC2" 216 | type = string 217 | default = null 218 | } 219 | 220 | variable "decode_authorization_messages" { 221 | description = "Enable automatic decoding of any encoded authorization (error) messages using the sts:DecodeAuthorizationMessage API" 222 | type = bool 223 | default = null 224 | } 225 | 226 | variable "insecure_skip_tls_verify" { 227 | description = "This allows skipping TLS verification of the AWS EC2 endpoint. The default is `false`" 228 | type = bool 229 | default = null 230 | } 231 | 232 | variable "max_retries" { 233 | description = "This is the maximum number of times an API call is retried, in the case where requests are being throttled or experiencing transient failures. The delay between the subsequent API calls increases exponentially" 234 | type = number 235 | default = null 236 | } 237 | 238 | variable "mfa_code" { 239 | description = "The MFA TOTP code. This should probably be a user variable since it changes all the time" 240 | type = string 241 | default = null 242 | } 243 | 244 | variable "profile" { 245 | description = "The profile to use in the shared credentials file for AWS" 246 | type = string 247 | default = null 248 | } 249 | 250 | variable "region" { 251 | description = "The name of the region, such as us-east-1, in which to launch the EC2 instance to create the AMI" 252 | type = string 253 | default = "us-west-2" 254 | } 255 | 256 | variable "secret_key" { 257 | description = "The secret key used to communicate with AWS" 258 | type = string 259 | default = null 260 | } 261 | 262 | variable "shared_credentials_file" { 263 | description = "Path to a credentials file to load credentials from" 264 | type = string 265 | default = null 266 | } 267 | 268 | variable "skip_credential_validation" { 269 | description = "Set to true if you want to skip validating AWS credentials before runtime" 270 | type = bool 271 | default = null 272 | } 273 | 274 | variable "skip_metadata_api_check" { 275 | description = "Skip Metadata Api Check" 276 | type = bool 277 | default = null 278 | } 279 | 280 | variable "token" { 281 | description = "The access token to use. This is different from the access key and secret key" 282 | type = string 283 | default = null 284 | } 285 | 286 | # Communicator 287 | 288 | variable "communicator" { 289 | description = "The communicator to use to communicate with the EC2 instance. Valid values are `none`, `ssh`, `winrm`, and `ssh+winrm`" 290 | type = string 291 | default = "ssh" 292 | } 293 | 294 | variable "pause_before_connecting" { 295 | description = "We recommend that you enable SSH or WinRM as the very last step in your guest's bootstrap script, but sometimes you may have a race condition where you need Packer to wait before attempting to connect to your guest" 296 | type = string 297 | default = null 298 | } 299 | 300 | variable "ssh_agent_auth" { 301 | description = "If true, the local SSH agent will be used to authenticate connections to the source instance. No temporary keypair will be created, and the values of `ssh_password` and `ssh_private_key_file` will be ignored. The environment variable `SSH_AUTH_SOCK` must be set for this option to work properly" 302 | type = bool 303 | default = null 304 | } 305 | 306 | variable "ssh_bastion_agent_auth" { 307 | description = "If `true`, the local SSH agent will be used to authenticate with the bastion host. Defaults to `false`" 308 | type = bool 309 | default = null 310 | } 311 | 312 | variable "ssh_bastion_certificate_file" { 313 | description = "Path to user certificate used to authenticate with bastion host. The ~ can be used in path and will be expanded to the home directory of current user" 314 | type = string 315 | default = null 316 | } 317 | 318 | variable "ssh_bastion_host" { 319 | description = "A bastion host to use for the actual SSH connection" 320 | type = string 321 | default = null 322 | } 323 | 324 | variable "ssh_bastion_interactive" { 325 | description = "If `true`, the keyboard-interactive used to authenticate with bastion host" 326 | type = bool 327 | default = null 328 | } 329 | 330 | variable "ssh_bastion_password" { 331 | description = "The password to use to authenticate with the bastion host" 332 | type = string 333 | default = null 334 | } 335 | 336 | variable "ssh_bastion_port" { 337 | description = "The port of the bastion host. Defaults to `22`" 338 | type = number 339 | default = null 340 | } 341 | 342 | variable "ssh_bastion_private_key_file" { 343 | description = "Path to a PEM encoded private key file to use to authenticate with the bastion host. The `~` can be used in path and will be expanded to the home directory of current user" 344 | type = string 345 | default = null 346 | } 347 | 348 | variable "ssh_bastion_username" { 349 | description = "The username to connect to the bastion host" 350 | type = string 351 | default = null 352 | } 353 | 354 | variable "ssh_ciphers" { 355 | description = "This overrides the value of ciphers supported by default by Golang. The default value is `[\"aes128-gcm@openssh.com\", \"chacha20-poly1305@openssh.com\", \"aes128-ctr\", \"aes192-ctr\", \"aes256-ctr\"]`" 356 | type = list(string) 357 | default = null 358 | } 359 | 360 | variable "ssh_certificate_file" { 361 | description = "Path to user certificate used to authenticate with SSH. The `~` can be used in path and will be expanded to the home directory of current user" 362 | type = string 363 | default = null 364 | } 365 | 366 | variable "ssh_clear_authorized_keys" { 367 | description = "If true, Packer will attempt to remove its temporary key from `~/.ssh/authorized_keys` and `/root/.ssh/authorized_keys`" 368 | type = bool 369 | default = null 370 | } 371 | 372 | variable "ssh_disable_agent_forwarding" { 373 | description = "If `true`, SSH agent forwarding will be disabled. Defaults to `false`" 374 | type = bool 375 | default = null 376 | } 377 | 378 | variable "ssh_file_transfer_method" { 379 | description = "How to transfer files, Secure copy (`scp` default) or SSH File Transfer Protocol (`sftp`)" 380 | type = string 381 | default = null 382 | } 383 | 384 | variable "ssh_handshake_attempts" { 385 | description = "The number of handshakes to attempt with SSH once it can connect. This defaults to `10`, unless a `ssh_timeout` is set" 386 | type = number 387 | default = null 388 | } 389 | 390 | variable "ssh_host" { 391 | description = "The address to SSH to. This usually is automatically configured by the builder" 392 | type = string 393 | default = null 394 | } 395 | 396 | variable "ssh_interface" { 397 | description = "One of `public_ip`, `private_ip`, `public_dns`, `private_dns` or `session_manager`. If set, either the public IP address, private IP address, public DNS name or private DNS name will be used as the host for SSH. The default behavior if inside a VPC is to use the public IP address if available, otherwise the private IP address will be used. If not in a VPC the public DNS name will be used" 398 | type = string 399 | default = "public_dns" 400 | } 401 | 402 | variable "ssh_keep_alive_interval" { 403 | description = "How often to send \"keep alive\" messages to the server. Set to a negative value (`-1s`) to disable. Defaults to `5s`" 404 | type = string 405 | default = null 406 | } 407 | 408 | variable "ssh_key_exchange_algorithms" { 409 | description = "If set, Packer will override the value of key exchange (kex) algorithms supported by default by Golang. Acceptable values include: `curve25519-sha256@libssh.org`, `ecdh-sha2-nistp256`, `ecdh-sha2-nistp384`, `ecdh-sha2-nistp521`, `diffie-hellman-group14-sha1`, and `diffie-hellman-group1-sha1`" 410 | type = list(string) 411 | default = null 412 | } 413 | 414 | variable "ssh_keypair_name" { 415 | description = "If specified, this is the key that will be used for SSH with the machine. The key must match a key pair name loaded up into the remote" 416 | type = string 417 | default = null 418 | } 419 | 420 | variable "ssh_local_tunnels" { 421 | description = "A list of local tunnels to use when connecting to the host" 422 | type = list(string) 423 | default = null 424 | } 425 | 426 | variable "ssh_password" { 427 | description = "A plaintext password to use to authenticate with SSH" 428 | type = string 429 | default = null 430 | } 431 | 432 | variable "ssh_port" { 433 | description = "The port to connect to SSH. This defaults to `22`" 434 | type = number 435 | default = null 436 | } 437 | 438 | variable "ssh_private_key_file" { 439 | description = "Path to a PEM encoded private key file to use to authenticate with SSH. The ~ can be used in path and will be expanded to the home directory of current user" 440 | type = string 441 | default = null 442 | } 443 | 444 | variable "ssh_proxy_host" { 445 | description = "A SOCKS proxy host to use for SSH connection" 446 | type = string 447 | default = null 448 | } 449 | 450 | variable "ssh_proxy_password" { 451 | description = "The optional password to use to authenticate with the proxy server" 452 | type = string 453 | default = null 454 | } 455 | 456 | variable "ssh_proxy_port" { 457 | description = "A port of the SOCKS proxy. Defaults to `1080`" 458 | type = number 459 | default = null 460 | } 461 | 462 | variable "ssh_proxy_username" { 463 | description = "The optional username to authenticate with the proxy server" 464 | type = string 465 | default = null 466 | } 467 | # 468 | variable "ssh_pty" { 469 | description = "If `true`, a PTY will be requested for the SSH connection. This defaults to `false`" 470 | type = bool 471 | default = null 472 | } 473 | 474 | variable "ssh_read_write_timeout" { 475 | description = "The amount of time to wait for a remote command to end. This might be useful if, for example, packer hangs on a connection after a reboot. Example: `5m`. Disabled by default" 476 | type = string 477 | default = null 478 | } 479 | 480 | variable "ssh_remote_tunnels" { 481 | description = "A list of remote tunnels to use when connecting to the host" 482 | type = list(string) 483 | default = null 484 | } 485 | 486 | variable "ssh_timeout" { 487 | description = "The time to wait for SSH to become available. Packer uses this to determine when the machine has booted so this is usually quite long. This defaults to `5m`, unless `ssh_handshake_attempts` is set" 488 | type = string 489 | default = null 490 | } 491 | 492 | variable "ssh_username" { 493 | description = "The username to connect to SSH with. Required if using SSH" 494 | type = string 495 | default = "ec2-user" 496 | } 497 | 498 | variable "temporary_key_pair_type" { 499 | description = "Specifies the type of key to create. The possible values are 'dsa', 'ecdsa', 'ed25519', or 'rsa'. Default is `rsa`" 500 | type = string 501 | default = null 502 | } 503 | 504 | variable "temporary_key_pair_bits" { 505 | description = "Specifies the number of bits in the key to create. For RSA keys, the minimum size is 1024 bits and the default is 4096 bits. Generally, 3072 bits is considered sufficient" 506 | type = number 507 | default = null 508 | } 509 | 510 | # Run Configuration 511 | 512 | variable "associate_public_ip_address" { 513 | description = "If using a non-default VPC, public IP addresses are not provided by default. If this is true, your new instance will get a Public IP" 514 | type = bool 515 | default = null 516 | } 517 | 518 | variable "capacity_reservation_preference" { 519 | description = "Set the preference for using a capacity reservation if one exists. Either will be `open` or `none`. Defaults to `none`" 520 | type = string 521 | default = null 522 | } 523 | 524 | variable "capacity_reservation_group_arn" { 525 | description = "Provide the EC2 Capacity Reservation Group ARN that will be used by Packer" 526 | type = string 527 | default = null 528 | } 529 | 530 | variable "capacity_reservation_id" { 531 | description = "Provide the specific EC2 Capacity Reservation ID that will be used by Packer" 532 | type = string 533 | default = null 534 | } 535 | 536 | variable "disable_stop_instance" { 537 | description = "If this is set to true, Packer will not stop the instance but will assume that you will send the stop signal yourself through your final provisioner" 538 | type = bool 539 | default = null 540 | } 541 | 542 | variable "ebs_optimized" { 543 | description = "Mark instance as EBS Optimized. Default `false`" 544 | type = bool 545 | default = null 546 | } 547 | 548 | variable "enable_nitro_enclave" { 549 | description = "Enable support for Nitro Enclaves on the instance" 550 | type = bool 551 | default = null 552 | } 553 | 554 | variable "enable_unlimited_credits" { 555 | description = "Enabling Unlimited credits allows the source instance to burst additional CPU beyond its available CPU Credits for as long as the demand exists" 556 | type = bool 557 | default = null 558 | } 559 | 560 | variable "iam_instance_profile" { 561 | description = "The name of an IAM instance profile to launch the EC2 instance with" 562 | type = string 563 | default = null 564 | } 565 | 566 | variable "instance_type" { 567 | description = "The EC2 instance type to use while building the AMI, such as `m5.large`" 568 | type = string 569 | default = "c5.xlarge" 570 | } 571 | 572 | variable "fleet_tags" { 573 | description = "Key/value pair tags to apply tags to the fleet that is issued" 574 | type = map(string) 575 | default = null 576 | } 577 | 578 | variable "pause_before_ssm" { 579 | description = "The time to wait before establishing the Session Manager session" 580 | type = string 581 | default = null 582 | } 583 | 584 | variable "placement" { 585 | description = "Describes the placement of an instance" 586 | type = map(string) 587 | default = {} 588 | } 589 | 590 | variable "run_tags" { 591 | description = "Key/value pair tags to apply to the generated key-pair, security group, iam profile and role, snapshot, network interfaces and instance that is launched to create the EBS volumes. The resulting AMI will also inherit these tags" 592 | type = map(string) 593 | default = null 594 | } 595 | 596 | variable "security_group_ids" { 597 | description = "A list of security group IDs to assign to the instance. By default this is not set and Packer will automatically create a new temporary security group to allow SSH access" 598 | type = list(string) 599 | default = null 600 | } 601 | 602 | variable "security_group_filter" { 603 | description = "Filters used to populate the `security_group_ids` field. `security_group_ids` take precedence over this" 604 | type = list(map(string)) 605 | default = [] 606 | } 607 | 608 | variable "session_manager_port" { 609 | description = "Which port to connect the local end of the session tunnel to. If left blank, Packer will choose a port for you from available ports. This option is only used when `ssh_interface` is set `session_manager`" 610 | type = number 611 | default = null 612 | } 613 | 614 | variable "shutdown_behavior" { 615 | description = "Automatically terminate instances on shutdown in case Packer exits ungracefully. Possible values are `stop` and `terminate`. Defaults to `stop`" 616 | type = string 617 | default = null 618 | } 619 | 620 | variable "skip_profile_validation" { 621 | description = "Whether or not to check if the IAM instance profile exists. Defaults to `false`" 622 | type = bool 623 | default = null 624 | } 625 | 626 | variable "subnet_filter" { 627 | description = "Filters used to populate the subnet_id field. `subnet_id` take precedence over this" 628 | type = list(map(string)) 629 | default = [] 630 | } 631 | 632 | variable "subnet_id" { 633 | description = "f using VPC, the ID of the subnet, such as subnet-12345def, where Packer will launch the EC2 instance. This field is required if you are using an non-default VPC" 634 | type = string 635 | default = null 636 | } 637 | 638 | variable "temporary_security_group_source_cidrs" { 639 | description = "A list of IPv4 CIDR blocks to be authorized access to the instance, when packer is creating a temporary security group. The default is `[0.0.0.0/0]`" 640 | type = list(string) 641 | default = null 642 | } 643 | 644 | variable "temporary_security_group_source_public_ip" { 645 | description = "When enabled, use public IP of the host (obtained from https://checkip.amazonaws.com) as CIDR block to be authorized access to the instance, when packer is creating a temporary security group. Defaults to `false`" 646 | type = bool 647 | default = null 648 | } 649 | 650 | variable "user_data" { 651 | description = "User data to apply when launching the instance" 652 | type = string 653 | default = null 654 | } 655 | 656 | variable "user_data_file" { 657 | description = "Path to a file that will be used for the user data when launching the instance" 658 | type = string 659 | default = null 660 | } 661 | 662 | variable "vpc_filter" { 663 | description = "Filters used to populate the `vpc_id` field. `vpc_id` take precedence over this" 664 | type = list(map(string)) 665 | default = [] 666 | } 667 | 668 | variable "vpc_id" { 669 | description = "If launching into a VPC subnet, Packer needs the VPC ID in order to create a temporary security group within the VPC. Requires `subnet_id` to be set. If this field is left blank, Packer will try to get the VPC ID from the `subnet_id`" 670 | type = string 671 | default = null 672 | } 673 | 674 | variable "metadata_options" { 675 | description = "Configures the metadata options for the instance launched" 676 | type = map(string) 677 | default = { 678 | http_endpoint = "enabled" 679 | http_tokens = "required" 680 | http_put_response_hop_limit = 1 681 | } 682 | } 683 | 684 | ################################################################################ 685 | # Build 686 | ################################################################################ 687 | 688 | variable "shell_provisioner1" { 689 | description = "Values passed to the first shell provisioner" 690 | default = {} 691 | } 692 | 693 | variable "shell_provisioner2" { 694 | description = "Values passed to the second shell provisioner" 695 | default = {} 696 | } 697 | 698 | variable "shell_provisioner3" { 699 | description = "Values passed to the third/last shell provisioner" 700 | default = {} 701 | } 702 | -------------------------------------------------------------------------------- /terraform/eks.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "current" {} 2 | data "aws_availability_zones" "available" {} 3 | 4 | locals { 5 | ####### set this to the AMI-ID output by Packer #### 6 | custom_ami_id_amd64 = "ami-abc1234567890" 7 | custom_ami_id_arm64 = "ami-abc1234567890" 8 | #################################################### 9 | name = "webassembly-on-eks" 10 | cluster_version = "1.31" 11 | 12 | vpc_cidr = "10.0.0.0/16" 13 | azs = slice(data.aws_availability_zones.available.names, 0, 3) 14 | 15 | tags = { 16 | Example = local.name 17 | } 18 | } 19 | 20 | ################################################################################ 21 | # EKS Module 22 | ################################################################################ 23 | 24 | module "eks" { 25 | source = "git::https://github.com/terraform-aws-modules/terraform-aws-eks.git?ref=670aa8a79d48e13e70726b0809ac3add3914b58e" 26 | 27 | cluster_name = local.name 28 | cluster_version = local.cluster_version 29 | cluster_endpoint_public_access = true 30 | cluster_ip_family = "ipv6" 31 | create_cni_ipv6_iam_policy = true 32 | 33 | enable_cluster_creator_admin_permissions = true 34 | 35 | cluster_addons = { 36 | coredns = { 37 | most_recent = true 38 | } 39 | kube-proxy = { 40 | most_recent = true 41 | } 42 | vpc-cni = { 43 | most_recent = true 44 | before_compute = true 45 | } 46 | } 47 | 48 | vpc_id = module.vpc.vpc_id 49 | subnet_ids = module.vpc.private_subnets 50 | control_plane_subnet_ids = module.vpc.intra_subnets 51 | 52 | eks_managed_node_groups = { 53 | webassembly_amd64 = { 54 | attach_cluster_primary_security_group = true 55 | iam_role_attach_cni_policy = true 56 | min_size = 2 57 | max_size = 3 58 | desired_size = 2 59 | instance_types = ["c6i.xlarge"] 60 | ami_type = "CUSTOM" 61 | platform = "linux" 62 | ami_id = local.custom_ami_id_amd64 63 | user_data_template_path = "${path.module}/templates/user-data.tpl" 64 | iam_role_additional_policies = { 65 | AmazonEC2ContainerRegistryReadOnly = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" 66 | AmazonSSMManagedInstanceCore = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" 67 | } 68 | } 69 | webassembly_arm64 = { 70 | attach_cluster_primary_security_group = true 71 | iam_role_attach_cni_policy = true 72 | min_size = 2 73 | max_size = 3 74 | desired_size = 2 75 | instance_types = ["c6g.xlarge"] 76 | ami_type = "CUSTOM" 77 | platform = "linux" 78 | ami_id = local.custom_ami_id_arm64 79 | user_data_template_path = "${path.module}/templates/user-data.tpl" 80 | iam_role_additional_policies = { 81 | AmazonEC2ContainerRegistryReadOnly = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" 82 | AmazonSSMManagedInstanceCore = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" 83 | } 84 | } 85 | } 86 | 87 | tags = local.tags 88 | } 89 | 90 | ################################################################################ 91 | # Supporting Resources 92 | ################################################################################ 93 | 94 | module "vpc" { 95 | source = "git::https://github.com/terraform-aws-modules/terraform-aws-vpc.git?ref=4a2809c673afa13097af98c2e3c553da8db766a9" 96 | 97 | name = local.name 98 | cidr = local.vpc_cidr 99 | 100 | azs = local.azs 101 | private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)] 102 | public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)] 103 | intra_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 52)] 104 | 105 | enable_nat_gateway = true 106 | single_nat_gateway = true 107 | enable_ipv6 = true 108 | create_egress_only_igw = true 109 | 110 | public_subnet_ipv6_prefixes = [0, 1, 2] 111 | public_subnet_assign_ipv6_address_on_creation = true 112 | private_subnet_ipv6_prefixes = [3, 4, 5] 113 | private_subnet_assign_ipv6_address_on_creation = true 114 | intra_subnet_ipv6_prefixes = [6, 7, 8] 115 | intra_subnet_assign_ipv6_address_on_creation = true 116 | 117 | public_subnet_tags = { 118 | "kubernetes.io/role/elb" = 1 119 | } 120 | 121 | private_subnet_tags = { 122 | "kubernetes.io/role/internal-elb" = 1 123 | } 124 | 125 | tags = local.tags 126 | } 127 | 128 | module "ecr" { 129 | source = "git::https://github.com/terraform-aws-modules/terraform-aws-ecr.git?ref=df965a8501c9256c1893bb9d65fc2c037ffa1257" 130 | 131 | repository_name = "wasm-example" 132 | 133 | repository_lifecycle_policy = jsonencode({ 134 | rules = [ 135 | { 136 | rulePriority = 1, 137 | description = "Keep last 7 images", 138 | selection = { 139 | tagStatus = "tagged", 140 | tagPrefixList = ["v"], 141 | countType = "imageCountMoreThan", 142 | countNumber = 30 143 | }, 144 | action = { 145 | type = "expire" 146 | } 147 | } 148 | ] 149 | }) 150 | 151 | tags = { 152 | Terraform = "true" 153 | Environment = "dev" 154 | } 155 | } 156 | 157 | module "ecr-microservice" { 158 | source = "git::https://github.com/terraform-aws-modules/terraform-aws-ecr.git?ref=df965a8501c9256c1893bb9d65fc2c037ffa1257" 159 | 160 | repository_name = "microservice" 161 | 162 | repository_lifecycle_policy = jsonencode({ 163 | rules = [ 164 | { 165 | rulePriority = 1, 166 | description = "Keep last 7 images", 167 | selection = { 168 | tagStatus = "tagged", 169 | tagPrefixList = ["v"], 170 | countType = "imageCountMoreThan", 171 | countNumber = 30 172 | }, 173 | action = { 174 | type = "expire" 175 | } 176 | } 177 | ] 178 | }) 179 | 180 | tags = { 181 | Terraform = "true" 182 | Environment = "dev" 183 | } 184 | } -------------------------------------------------------------------------------- /terraform/providers.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "5.70.0" 6 | } 7 | } 8 | } 9 | 10 | provider "aws" { 11 | ######## set this to the same region as you did for packer ######## 12 | region = "aa-example-1" 13 | ################################################################### 14 | } -------------------------------------------------------------------------------- /terraform/templates/user-data.tpl: -------------------------------------------------------------------------------- 1 | MIME-Version: 1.0 2 | Content-Type: multipart/mixed; boundary="BOUNDARY" 3 | 4 | --BOUNDARY 5 | Content-Type: application/node.eks.aws 6 | 7 | apiVersion: node.eks.aws/v1alpha1 8 | kind: NodeConfig 9 | spec: 10 | cluster: 11 | name: ${cluster_name} 12 | apiServerEndpoint: ${cluster_endpoint} 13 | certificateAuthority: ${cluster_auth_base64} 14 | cidr: ${cluster_service_cidr} 15 | --BOUNDARY-- --------------------------------------------------------------------------------