8000 feat(examples/templates): add `docker-devcontainer` template and rename envbuilder template by mafredri · Pull Request #18741 · coder/coder · GitHub
[go: up one dir, main page]

Skip to content

feat(examples/templates): add docker-devcontainer template and rename envbuilder template #18741

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jul 3, 2025
Prev Previous commit
Next Next commit
move script to coder_script
  • Loading branch information
mafredri committed Jul 3, 2025
commit b9a3b721280143e136838ae5f3991d11f0651465
83 changes: 9 additions & 74 deletions examples/templates/docker-devcontainer/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -53,80 +53,6 @@ resource "coder_agent" "main" {
touch ~/.init_done
fi

if [ "$${CODER_AGENT_URL#*host.docker.internal}" != "$CODER_AGENT_URL" ]; then
# If the access URL is host.docker.internal, we set up forwarding
# to the host Docker gateway IP address, which is typically
# 172.17.0.1, this will allow the devcontainers to access the
# Coder server even if the access URL has been shadowed by a
# "docker0" interface. This usually happens if docker is started
# inside a devcontainer.
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
sudo iptables -t nat -A POSTROUTING -j MASQUERADE

# Get the IP address of the host Docker gateway, which is
# typically 172.17.0.1 and set up port forwarding between this
# workspace's Docker gateway and the host Docker gateway.
host_ip=$(getent hosts host.docker.internal | awk '{print $1}')
port="$${CODER_AGENT_URL##*:}"
port="$${port%%/*}"
case "$port" in
[0-9]*)
sudo iptables -t nat -A PREROUTING -p tcp --dport $port -j DNAT --to-destination $host_ip:$port
echo "Forwarded port $port to $host_ip"
;;
*)
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination $host_ip:80
sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-destination $host_ip:443
echo "Forwarded default ports 80/443 to $host_ip"
;;
esac

# Start the docker service if it is not running, this will create
# the "docker0" interface if it does not exist.
sudo service docker start

# Since we cannot define "--add-host" for devcontainers, we define
# a dnsmasq configuration that allows devcontainers to resolve the
# host.docker.internal URL to this workspace, which is typically
# 172.18.0.1. Note that we take the second IP address from
# "hostname -I" because the first one is usually in the range
# 172.17.0.0/16, which is the host Docker bridge.
dns_ip=
while [ -z "$dns_ip" ]; do
dns_ip=$(hostname -I | awk '{print $2}')
if [ -z "$dns_ip" ]; then
echo "Waiting for hostname -I to return a valid second IP address..."
sleep 1
fi
done

# Create a simple dnsmasq configuration to allow devcontainers to
# resolve host.docker.internal.
sudo apt-get update -y
sudo apt-get install -y dnsmasq

echo "no-hosts" | sudo tee /etc/dnsmasq.conf
echo "address=/host.docker.internal/$dns_ip" | sudo tee -a /etc/dnsmasq.conf
echo "resolv-file=/etc/resolv.conf" | sudo tee -a /etc/dnsmasq.conf
echo "no-dhcp-interface=" | sudo tee -a /etc/dnsmasq.conf
echo "bind-interfaces" | sudo tee -a /etc/dnsmasq.conf
echo "listen-address=127.0.0.1,$dns_ip" | sudo tee -a /etc/dnsmasq.conf

# Restart dnsmasq to apply the new configuration.
sudo service dnsmasq restart

# Configure Docker to use the dnsmasq server for DNS resolution.
# This allows devcontainers to resolve host.docker.internal to the
# IP address of this workspace.
echo "{\"dns\": [\"$dns_ip\"]}"| sudo tee /etc/docker/daemon.json

# Restart the Docker service to apply the new configuration.
sudo service docker restart
else
# Start the docker service if it is not running.
sudo service docker start
fi

# Add any commands that should be executed at workspace startup
# (e.g. install requirements, start a program, etc) here.
EOT
Expand Down Expand Up @@ -225,6 +151,15 @@ resource "coder_agent" "main" {
}
}

resource "coder_script" "init_docker_in_docker" {
count = data.coder_workspace.me.start_count
agent_id = coder_agent.main.id
display_name = "Initialize Docker-in-Docker"
run_on_start = true
icon = "/icon/docker.svg"
script = file("${path.module}/scripts/init-docker-in-docker.sh")
}

# See https://registry.coder.com/modules/coder/devcontainers-cli
module "devcontainers-cli" {
count = data.coder_workspace.me.start_count
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/bin/sh
set -e

if [ "${CODER_AGENT_URL#*host.docker.internal}" = "$CODER_AGENT_URL" ]; then
# This is likely an external access URL, so we do not need to set up
# port forwarding or DNS resolution for host.docker.internal.

# Start the docker service if it is not running.
sudo service docker start

exit 0
fi

# The access URL is host.docker.internal, so we must set up forwarding
# to the host Docker gateway IP address, which is typically 172.17.0.1,
# this will allow the devcontainers to access the Coder server even if
# the access URL has been shadowed by a "docker0" interface. This
# usually happens if docker is started inside a devcontainer.

# Enable IP forwarding to allow traffic to flow between the host and
# the devcontainers.
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
sudo iptables -t nat -A POSTROUTING -j MASQUERADE

# Get the IP address of the host Docker gateway, which is
# typically 172.17.0.1 and set up port forwarding between this
# workspace's Docker gateway and the host Docker gateway.
host_ip=$(getent hosts host.docker.internal | awk '{print $1}')
port="${CODER_AGENT_URL##*:}"
port="${port%%/*}"
case "$port" in
[0-9]*)
sudo iptables -t nat -A PREROUTING -p tcp --dport $port -j DNAT --to-destination $host_ip:$port
echo "Forwarded port $port to $host_ip"
;;
*)
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination $host_ip:80
sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-destination $host_ip:443
echo "Forwarded default ports 80/443 to $host_ip"
;;
esac

# Start the docker service if it is not running, this will create
# the "docker0" interface if it does not exist.
sudo service docker start

# Since we cannot define "--add-host" for devcontainers, we define
# a dnsmasq configuration that allows devcontainers to resolve the
# host.docker.internal URL to this workspace, which is typically
# 172.18.0.1. Note that we take the second IP address from
# "hostname -I" because the first one is usually in the range
# 172.17.0.0/16, which is the host Docker bridge.
dns_ip=
while [ -z "$dns_ip" ]; do
dns_ip=$(hostname -I | awk '{print $2}')
if [ -z "$dns_ip" ]; then
echo "Waiting for hostname -I to return a valid second IP address..."
sleep 1
fi
done

# Create a simple dnsmasq configuration to allow devcontainers to
# resolve host.docker.internal.
sudo apt-get update -y
sudo apt-get install -y dnsmasq

echo "no-hosts" | sudo tee /etc/dnsmasq.conf
echo "address=/host.docker.internal/$dns_ip" | sudo tee -a /etc/dnsmasq.conf
echo "resolv-file=/etc/resolv.conf" | sudo tee -a /etc/dnsmasq.conf
echo "no-dhcp-interface=" | sudo tee -a /etc/dnsmasq.conf
echo "bind-interfaces" | sudo tee -a /etc/dnsmasq.conf
echo "listen-address=127.0.0.1,$dns_ip" | sudo tee -a /etc/dnsmasq.conf

# Restart dnsmasq to apply the new configuration.
sudo service dnsmasq restart

# Configure Docker to use the dnsmasq server for DNS resolution.
# This allows devcontainers to resolve host.docker.internal to the
# IP address of this workspace.
echo "{\"dns\": [\"$dns_ip\"]}" | sudo tee /etc/docker/daemon.json

# Restart the Docker service to apply the new configuration.
sudo service docker restart
Loading
0