This example demonstrates running gopherstack as a backend (i.e. the
"AWS API" lives in one process, your application / frontend / CI pipeline
lives outside it) while the EC2 service is configured with the docker
compute provider so RunInstances actually launches a real Docker
container with a working sshd.
The launched container ships an OpenSSH daemon and the public key from the
EC2 key pair the caller created is wired into
/home/ec2-user/.ssh/authorized_keys, so callers can ssh ec2-user@<host>
into a real shell.
┌──────────────────────────────────────┐ ┌──────────────────────────┐
│ host (your laptop / CI runner) │ │ docker daemon │
│ │ │ │
│ demo.sh ──► aws ec2 … │ │ ┌────────────────────┐ │
│ ──► dig @127.0.0.1 -p 10053 │ │ │ gopherstack │ │
│ ──► ssh -p 22000 ec2-user@… │ │ │ :8000 (HTTP API) │ │
│ │ │ │ :10053 (DNS) │ │
└────────┬─────────────────────────────┘ │ └─────┬──────────────┘ │
│ │ │ │
│ host ports 8000 / 10053 / 22000+ │ ▼ │
└─────────────────────────────────►│ ┌────────────────────┐ │
│ │ gopherstack-i-… │ │
│ │ (sshd, ec2-user) │ │
│ │ port 22 → host │ │
│ │ 22000…22019 │ │
│ └────────────────────┘ │
└──────────────────────────┘
Key points:
demo.shruns on the host, not inside the compose stack, so the same flow works for any frontend that talks to gopherstack over HTTP from a separate process.- gopherstack publishes three things on the docker host:
:8000— the AWS-compatible HTTP API.:10053/udp— the embedded DNS server, where the syntheticec2-<id>.compute-1.amazonaws.comhostnames generated by the docker provider are registered. Frontends can resolve them withdigor by pointing their resolver at:10053.22000–22019— a small SSH port range. The docker provider picks a free port from this range per launched instance andaws ec2 describe-instancesexposes it as thegopherstack:ssh-porttag.
aws ec2 create-key-pair --key-name ec2-docker-demoand saves the PEM.aws ec2 run-instances --image-id ami-… --instance-type t3.micro --key-name …to trigger a container launch through the docker compute provider.- Polls
aws ec2 describe-instancesuntilState=runningand thePublicDnsNameplus thegopherstack:ssh-host/gopherstack:ssh-porttags are populated. dig @127.0.0.1 -p 10053 +short <PublicDnsName>to resolve the synthetic hostname through the embedded DNS server.ssh -p <ssh-port> -i …pem ec2-user@<resolved-ip>and runsecho "hello world from $(hostname)".aws ec2 terminate-instances …anddelete-key-pairto clean up.
cd examples/ec2-docker
docker compose up -d --build
docker compose ps # wait for healthy
./demo.sh
docker compose down --remove-orphansExpected output (truncated):
ec2-3b492e3c6823a.compute-1.amazonaws.com -> 127.0.0.1
sshd is up after 2s
hello world from i-3b492e3c6823a
=== SUCCESS: round-tripped through the docker-backed EC2 instance ===
demo.sh reads ENDPOINT, DNS_ADDR, DNS_PORT, KEY_NAME, KEY_FILE
and AMI_ID from the environment if you want to point it at a remote
gopherstack or change the key location.
DescribeInstances returns the AWS-style hostname and two
gopherstack-specific tags so the integration is one HTTP call:
aws --endpoint-url http://localhost:8000 ec2 describe-instances \
--instance-ids i-3b492e3c6823a \
--query 'Reservations[0].Instances[0].{
Dns: PublicDnsName,
Host: Tags[?Key==`gopherstack:ssh-host`]|[0].Value,
Port: Tags[?Key==`gopherstack:ssh-port`]|[0].Value
}'You can either ssh by IP+port (the Host/Port tags) or by hostname+port
after pointing your resolver at the embedded DNS:
# /etc/resolv.conf snippet on the calling machine:
# nameserver 127.0.0.1
# port 10053
ssh -p 22000 -i key.pem ec2-user@ec2-3b492e3c6823a.compute-1.amazonaws.comThe provider is configured via environment variables / CLI flags:
| Flag | Env var | Default | Description |
|---|---|---|---|
--ec2-provider |
EC2_PROVIDER |
inmemory |
Set to docker to enable the docker compute provider. |
--ec2-docker-image |
EC2_DOCKER_IMAGE |
amazonlinux:2 |
Docker image used for new instances. |
--ec2-docker-network |
EC2_DOCKER_NETWORK |
(empty) | Docker network the launched containers attach to (empty = default bridge). |
--ec2-docker-ssh-host-ip |
EC2_DOCKER_SSH_HOST_IP |
127.0.0.1 |
Host IP that mapped sshd ports bind to (use 0.0.0.0 to expose externally). |
--ec2-docker-ssh-port-min |
EC2_DOCKER_SSH_PORT_MIN |
0 |
Lower bound of the host TCP port range used to map sshd (0 = let Docker pick). |
--ec2-docker-ssh-port-max |
EC2_DOCKER_SSH_PORT_MAX |
0 |
Upper bound of the host TCP port range used to map sshd. |
--dns-addr |
DNS_ADDR |
(empty) | Bind address for the embedded DNS server (e.g. :10053). Empty = disabled. |
--dns-resolve-ip |
DNS_RESOLVE_IP |
127.0.0.1 |
IP address synthetic hostnames resolve to. |