feat(pulumi/examples): add generic aws ec2 instance

This commit is contained in:
Michele Cereda
2024-06-08 01:29:02 +02:00
parent a90763356c
commit ec7e57d974
11 changed files with 227 additions and 4 deletions

View File

@@ -0,0 +1,2 @@
set -x PULUMI_BACKEND_URL 'file://.'
set -x PULUMI_CONFIG_PASSPHRASE 'test123'

View File

@@ -0,0 +1,3 @@
/bin/
/node_modules/
/package-lock.json

View File

@@ -0,0 +1,8 @@
encryptionsalt: v1:55yDA5Kuyzs=:v1:+kFXkziA9Bd7nNZQ:OSBtNRAVCGBXwzTtHOGA5Ti9Dz+FTQ==
config:
aws:region: eu-west-1
aws:defaultTags:
tags:
ManagedByPulumi: true
Owner: "somebody@example.com"
PulumiProject: ec2-instance

View File

@@ -0,0 +1,9 @@
name: ec2-instance
runtime: nodejs
description: AWS EC2 instance example
config:
pulumi:tags:
value:
pulumi:template: aws-typescript
backend:
url: file://.

View File

@@ -0,0 +1,122 @@
import * as aws from "@pulumi/aws";
import * as cloudinit from "@pulumi/cloudinit";
import * as yaml from "yaml";
const ami = aws.ec2.getAmiOutput({
owners: [ "amazon", ],
nameRegex: "^al2023-ami-2023.*",
filters: [
{
name: "architecture",
values: [ "arm64" ],
},
{
name: "state",
values: [ "available" ],
},
],
mostRecent: true,
});
const keyPair = aws.ec2.getKeyPairOutput({ keyName: "somebody-ec2Instances" });
const subnet = aws.ec2.getSubnetOutput({
filters: [{
name: "tag:Name",
values: [ "Private C" ],
}],
});
const securityGroup = new aws.ec2.SecurityGroup(
"ec2-instance-example",
{
name: "Ec2InstanceExample",
description: "Regulate communications to and from the EC2 Instance",
tags: {
Name: "EC2 Instance Example",
},
},
);
const role = new aws.iam.Role(
"ec2-instance-example",
{
name: "Ec2InstanceExample",
assumeRolePolicy: JSON.stringify({
Version: "2012-10-17",
Statement: [{
Effect: "Allow",
Action: "sts:AssumeRole",
Principal: {
Service: "ec2.amazonaws.com",
},
}],
}),
managedPolicyArns: [ "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" ],
},
);
const instanceProfile = new aws.iam.InstanceProfile(
"ec2-instance-example",
{
name: "Ec2InstanceExample",
role: role.name,
},
);
const userData = new cloudinit.Config(
"ec2-instance-example",
{
gzip: true,
base64Encode: true,
parts: [
{
contentType: "text/cloud-config",
content: yaml.stringify({
package_upgrade: false,
packages: [ "amazon-ssm-agent" ],
runcmd: [
"systemctl daemon-reload",
"systemctl enable --now 'amazon-ssm-agent.service'",
]
}),
filename: "cloud-config.managed-by.ssm.yml",
},
{
contentType: "text/cloud-config",
content: yaml.stringify({
package_upgrade: false,
packages: [ "python" ],
}),
filename: "cloud-config.managed-by.ansible.yml",
mergeType: "dict(recurse_array,no_replace)+list(append)",
},
],
},
);
new aws.ec2.Instance(
"ec2-instance-example",
{
ami: ami.apply(ami => ami.id),
iamInstanceProfile: instanceProfile.name,
instanceType: "t4g.small",
keyName: keyPair.apply(keyPair => keyPair.keyName!),
rootBlockDevice: {
volumeType: "gp3",
volumeSize: 10,
tags: {
Description: "Instance root disk",
Name: "EC2 Instance Example",
},
},
subnetId: subnet.apply(subnet => subnet.id),
tags: {
Name: "EC2 Instance Example",
ManagedBySsm: "true",
ManagedByAnsible: "true",
},
userData: userData.rendered,
vpcSecurityGroupIds: [ securityGroup.id ],
},
{
ignoreChanges: [
// avoid being replaced just because a new version of the base image came out
"ami",
],
}
);

View File

@@ -0,0 +1,13 @@
{
"name": "ec2-instance",
"main": "index.ts",
"devDependencies": {
"@types/node": "^18",
"typescript": "^5.0.0"
},
"dependencies": {
"@pulumi/aws": "^6.0.0",
"@pulumi/cloudinit": "^1.0.0",
"yaml": "^2.0.0"
}
}

View File

@@ -0,0 +1,18 @@
{
"compilerOptions": {
"strict": true,
"outDir": "bin",
"target": "es2020",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"experimentalDecorators": true,
"pretty": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.ts"
]
}

View File

@@ -267,6 +267,7 @@ Examples:
- [Automating DNS-challenge based LetsEncrypt certificates with AWS Route 53]
- [Working with DB instance read replicas]
- AWS' [CLI]
- [Configuring EC2 Disk alert using Amazon CloudWatch]
### Sources
@@ -347,6 +348,7 @@ Examples:
[automating dns-challenge based letsencrypt certificates with aws route 53]: https://johnrix.medium.com/automating-dns-challenge-based-letsencrypt-certificates-with-aws-route-53-8ba799dd207b
[aws config tutorial by stephane maarek]: https://www.youtube.com/watch?v=qHdFoYSrUvk
[aws icons]: https://aws-icons.com/
[configuring ec2 disk alert using amazon cloudwatch]: https://medium.com/@chandinims001/configuring-ec2-disk-alert-using-amazon-cloudwatch-793807e40d72
[date & time policy conditions at aws - 1-minute iam lesson]: https://www.youtube.com/watch?v=4wpKP1HLEXg
[introduction to aws iam assumerole]: https://aws.plainenglish.io/introduction-to-aws-iam-assumerole-fbef3ce8e90b
[not authorized to perform: sts:assumerole]: https://repost.aws/questions/QUOY5XngCtRyOX4Desaygz8Q/not-authorized-to-perform-sts-assumerole

View File

@@ -29,22 +29,39 @@ aws ssm start-session \
aws ssm send-command \
--instance-ids 'i-0123456789abcdef0' \
--document-name 'AWS-RunShellScript' \
--parameters commands="echo 'hallo!'"
--parameters "commands="echo 'hallo'"
# Wait for commands execution.
aws ssm wait command-executed --instance-id 'i-0123456789abcdef0' --command-id 'abcdef01-2345-abcd-6789-abcdef012345'
# Get commands results.
aws ssm get-command-invocation --instance-id 'i-0123456789abcdef0' --command-id 'abcdef01-2345-abcd-6789-abcdef012345'
aws ssm get-command-invocation \
--instance-id 'i-0123456789abcdef0' --command-id 'abcdef01-2345-abcd-6789-abcdef012345' \
--query '{"status": Status, "rc": ResponseCode, "stdout": StandardOutputContent, "stderr": StandardErrorContent}'
```
</details>
<details>
<summary>Real world use cases</summary>
Also check out the [snippets].
```sh
# Connect to instances if they are available.
instance_id='i-08fc83ad07487d72f' \
&& eval $(aws ssm get-connection-status --target "$instance_id" --query "Status=='connected'" --output text) \
&& eval $(aws ssm get-connection-status --target "$instance_id" --query "Status=='connected'" --output 'text') \
&& aws ssm start-session --target "$instance_id" \
|| (echo "instance ${instance_id} not available" >&2 && false)
aws ssm send-command --instance-ids "i-08fc83ad07487d72f" \
--document-name "AWS-RunShellScript" --parameters commands="echo 'hallo!'"
# Run commands and get their output.
instance_id='i-0915612f182914822' \
&& command_id=$(aws ssm send-command --instance-ids "$instance_id" \
--document-name 'AWS-RunShellScript' --parameters 'commands="echo hallo"' \
--query 'Command.CommandId' --output 'text') \
&& aws ssm wait command-executed --command-id "$command_id" --instance-id "$instance_id" \
&& aws ssm get-command-invocation --command-id "$command_id" --instance-id "$instance_id" \
--query '{"status": Status, "rc": ResponseCode, "stdout": StandardOutputContent, "stderr": StandardErrorContent}'
```
</details>
@@ -267,6 +284,7 @@ $ sudo ssm-cli get-diagnostics --output 'table'
[amazon web services]: README.md
[cli]: cli.md
[ec2]: ec2.md
[snippets]: ../../../snippets/aws.fish
<!-- Upstream -->
[aws_ssm connection plugin notes]: https://docs.ansible.com/ansible/latest/collections/community/aws/aws_ssm_connection.html#notes

View File

@@ -73,3 +73,26 @@ aws ec2 describe-images --output 'yaml' \
aws iam list-instance-profiles | grep -i 'ssm'
sudo ssm-cli get-diagnostics --output 'table'
# Check instances are available
aws ssm get-connection-status --target "i-0915612ff82914822" --query "Status=='connected'" --output 'text'
# Connect to instances if they are available
instance_id='i-08fc83ad07487d72f' \
&& eval $(aws ssm get-connection-status --target "$instance_id" --query "Status=='connected'" --output 'text') \
&& aws ssm start-session --target "$instance_id" \
|| (echo "instance ${instance_id} not available" >&2 && false)
# Send commands
aws ssm send-command --instance-ids 'i-08fc83ad07487d72f' --document-name 'AWS-RunShellScript' --parameters "commands='echo hallo'"
aws ssm wait command-executed --command-id 'e5f7ca0e-4d74-4316-84be-9ccaf3ae1f70' --instance-id 'i-08fc83ad07487d72f'
aws ssm get-command-invocation --command-id 'e5f7ca0e-4d74-4316-84be-9ccaf3ae1f70' --instance-id 'i-08fc83ad07487d72f'
# Run commands and get their output.
set instance_id 'i-0915612f182914822' \
&& set command_id (aws ssm send-command --instance-ids "$instance_id" \
--document-name 'AWS-RunShellScript' --parameters 'commands="echo hallo"' \
--query 'Command.CommandId' --output 'text') \
&& aws ssm wait command-executed --command-id "$command_id" --instance-id "$instance_id" \
&& aws ssm get-command-invocation --command-id "$command_id" --instance-id "$instance_id" \
--query '{"status": Status, "rc": ResponseCode, "stdout": StandardOutputContent, "stderr": StandardErrorContent}'

View File

@@ -2,3 +2,8 @@
sudo systemctl enable --now 'gitlab-runner'
sudo journalctl -xefu 'gitlab-runner'
sudo hostnamectl
sudo hostnamectl status --static
sudo hostnamectl set-hostname --pretty 'prometheus'