scottslowe-learning-tools/docker/docker-ssh-pulumi/main.go
Scott Lowe 7ba159ad01 Add SSH-based Docker provider example
Add Go program illustrating use of an SSH-based Docker provider

Signed-off-by: Scott Lowe <scott.lowe@scottlowe.org>
2024-01-20 02:16:14 -07:00

188 lines
6.3 KiB
Go

package main
import (
"fmt"
"log"
"slices"
"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ec2"
awsx "github.com/pulumi/pulumi-awsx/sdk/v2/go/awsx/ec2"
"github.com/pulumi/pulumi-docker/sdk/v4/go/docker"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
"github.com/pulumiverse/pulumi-time/sdk/go/time"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
// Set up maps that are used later
channelNames := []string{"stable", "beta", "alpha", "lts"}
typeMap := map[string]string{"amd64": "t3a.small", "arm64": "t4g.small", "x86_64": "t3a.small", "x64": "t3a.small"}
// Retrieve configuration values
instanceCpuArch, err := config.Try(ctx, "architecture")
if err != nil {
instanceCpuArch = "arm64"
}
instanceType, ok := typeMap[instanceCpuArch]
if !ok {
instanceCpuArch = "arm64"
instanceType = "t4g.small"
}
if instanceCpuArch == "x86_64" || instanceCpuArch == "x64" {
instanceCpuArch = "amd64"
}
vpcNetworkCidr, err := config.Try(ctx, "networkcidr")
if err != nil {
vpcNetworkCidr = "10.0.0.0/16"
}
channel, err := config.Try(ctx, "channel")
if err != nil {
channel = "stable"
}
if !slices.Contains(channelNames, channel) {
channel = "stable"
}
userSuppliedKeyPair := config.Require(ctx, "keypair")
userSuppliedPrivateKeyFile := config.Require(ctx, "privatekeyfile")
// Create a new VPC, subnets, and associated infrastructure
dockerVpc, err := awsx.NewVpc(ctx, "docker-vpc", &awsx.VpcArgs{
CidrBlock: &vpcNetworkCidr,
EnableDnsHostnames: pulumi.Bool(true),
EnableDnsSupport: pulumi.Bool(true),
NatGateways: &awsx.NatGatewayConfigurationArgs{
Strategy: awsx.NatGatewayStrategyNone,
},
SubnetSpecs: []awsx.SubnetSpecArgs{
{
Type: awsx.SubnetTypePublic,
},
},
})
if err != nil {
log.Printf("error creating VPC: %s", err.Error())
}
// Create a Security Group that we can use to connect to our instance
dockerSg, err := ec2.NewSecurityGroup(ctx, "docker-sg", &ec2.SecurityGroupArgs{
VpcId: dockerVpc.VpcId,
Egress: ec2.SecurityGroupEgressArray{
ec2.SecurityGroupEgressArgs{
Protocol: pulumi.String("-1"),
FromPort: pulumi.Int(0),
ToPort: pulumi.Int(0),
CidrBlocks: pulumi.StringArray{pulumi.String("0.0.0.0/0")},
},
},
Ingress: ec2.SecurityGroupIngressArray{
ec2.SecurityGroupIngressArgs{
Protocol: pulumi.String("tcp"),
FromPort: pulumi.Int(22),
ToPort: pulumi.Int(22),
CidrBlocks: pulumi.StringArray{pulumi.String("0.0.0.0/0")},
},
ec2.SecurityGroupIngressArgs{
Protocol: pulumi.String("tcp"),
FromPort: pulumi.Int(2379),
ToPort: pulumi.Int(2380),
Description: pulumi.String("Allow etcd traffic from this security group"),
Self: pulumi.Bool(true),
},
ec2.SecurityGroupIngressArgs{
Protocol: pulumi.String("tcp"),
FromPort: pulumi.Int(4001),
ToPort: pulumi.Int(4001),
Description: pulumi.String("Allow etcd traffic from this security group"),
Self: pulumi.Bool(true),
},
ec2.SecurityGroupIngressArgs{
Protocol: pulumi.String("tcp"),
FromPort: pulumi.Int(7001),
ToPort: pulumi.Int(7001),
Description: pulumi.String("Allow etcd traffic from this security group"),
Self: pulumi.Bool(true),
},
},
})
if err != nil {
log.Printf("error creating security group: %s", err.Error())
}
// Get AMI ID for Flatcar Linux instance
amiName := fmt.Sprintf("Flatcar-%s-*", channel)
flatcarAmi, err := ec2.LookupAmi(ctx, &ec2.LookupAmiArgs{
Owners: []string{"075585003325"},
MostRecent: pulumi.BoolRef(true),
Filters: []ec2.GetAmiFilter{
{Name: "name", Values: []string{amiName}},
{Name: "root-device-type", Values: []string{"ebs"}},
{Name: "virtualization-type", Values: []string{"hvm"}},
{Name: "architecture", Values: []string{instanceCpuArch}},
},
})
if err != nil {
log.Printf("error looking up AMI: %s", err.Error())
}
// Launch an instance using Flatcar Linux AMI
flatcarInstance, err := ec2.NewInstance(ctx, "flatcar-instance", &ec2.InstanceArgs{
Ami: pulumi.String(flatcarAmi.Id),
InstanceType: pulumi.String(instanceType),
AssociatePublicIpAddress: pulumi.Bool(true),
KeyName: pulumi.StringPtr(userSuppliedKeyPair),
SubnetId: dockerVpc.PublicSubnetIds.Index(pulumi.Int(0)),
VpcSecurityGroupIds: pulumi.StringArray{dockerSg.ID()},
Tags: pulumi.StringMap{
"Name": pulumi.String("flatcar-instance"),
},
})
if err != nil {
log.Printf("error launching instance: %s", err.Error())
}
// Sleep for 15 seconds to allow instance to boot
instanceBootDelay, err := time.NewSleep(ctx, "instance-boot-delay", &time.SleepArgs{
CreateDuration: pulumi.String("20s"),
}, pulumi.DependsOn([]pulumi.Resource{flatcarInstance}))
if err != nil {
log.Printf("error generating delay: %s", err.Error())
}
// Create a new Docker provider
remoteDocker, err := docker.NewProvider(ctx, "remote-docker", &docker.ProviderArgs{
Host: pulumi.Sprintf("ssh://core@%s", flatcarInstance.PublicIp),
SshOpts: pulumi.StringArray{
pulumi.String("-i"), pulumi.String(userSuppliedPrivateKeyFile),
pulumi.String("-o"), pulumi.String("StrictHostKeyChecking=no"),
pulumi.String("-o"), pulumi.String("UserKnownHostsFile=/dev/null"),
},
}, pulumi.DependsOn([]pulumi.Resource{instanceBootDelay}))
if err != nil {
log.Printf("error creating provider: %s", err.Error())
}
// Pull down a container image on the remote host
nginxImage, err := docker.NewRemoteImage(ctx, "nginx-image", &docker.RemoteImageArgs{
Name: pulumi.String("nginx:1.17.4-alpine"),
}, pulumi.Provider(remoteDocker))
if err != nil {
log.Printf("error pulling remote image: %s", err.Error())
}
// Launch a container on the remote host
_, err = docker.NewContainer(ctx, "nginx-container", &docker.ContainerArgs{
Image: nginxImage.ImageId,
}, pulumi.Provider(remoteDocker))
if err != nil {
log.Printf("error creating remote container: %s", err.Error())
}
// Export some values as stack outputs
ctx.Export("instanceId", flatcarInstance.ID())
ctx.Export("instancePublicIpAddress", flatcarInstance.PublicIp)
ctx.Export("instancePrivateIpAddress", flatcarInstance.PrivateIp)
return nil
})
}