Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1a53751

Browse files
authored
Merge pull request #6 from bpmct/docker-limits
add docker-limits example
2 parents 9fb71fe + 7e2ff04 commit 1a53751

File tree

3 files changed

+308
-0
lines changed

3 files changed

+308
-0
lines changed

docker-limits/README.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# docker-with-limits
2+
3+
Coder template that provisions Docker images with limits for:
4+
5+
- Balanced CPU usage (1024 CPU shares)
6+
- RAM (2 GB max)
7+
- Disk (10GB max for overlayfs, for 10GB max for home volume)
8+
9+
## Requirements
10+
11+
- Sysbox container runtime
12+
- Secondary XFS block storage device mounted on `/var/lib/docker`
13+
- Linux Kernel 5.19+
14+
15+
> See below for instructions to meet these requirements.
16+
17+
## Sysbox container runtime
18+
19+
This template assumes you have the [sysbox container runtime](https://coder.com/docs/v2/latest/templates/docker-in-docker#sysbox-container-runtime) installed.
20+
21+
- Follow this documentation to [install Sysbox as a system package](https://github.com/nestybox/sysbox/blob/master/docs/user-guide/install-package.md)
22+
23+
## Set up XFS volume + quotas
24+
25+
This template will not work unless Docker is configured to work with overlay2/XFs, as Docker's default storage driver is not capable of disk quotas per-container. Keep reading to learn how to use Docker with overlay2/XFS.
26+
27+
> This was tested on an Ubuntu 22.04 virtual machine with a secondary disk attached as `/dev/sdb`. I referenced [this blog post](https://reece.tech/posts/docker-container-size-quota/) from reece.tech.
28+
29+
30+
1. Attach an secondary block disk to your VM, dedicated to Docker volumes.
31+
32+
1. Format the secondary as an XFS filesystem
33+
34+
```sh
35+
sudo mkfs.xfs /dev/sdb
36+
```
37+
38+
1. Modify `/etc/fstab` to mount the disk with support for quotas:
39+
40+
```sh
41+
# /etc/fstab
42+
43+
# ... other disks
44+
45+
/dev/sdb /var/lib/docker xfs defaults,quota,prjquota,pquota,gquota 0 0
46+
```
47+
48+
1. You may also need to enable uquota,pquota in your GRUB config:
49+
50+
```sh
51+
# /etc/default/grub
52+
53+
GRUB_CMDLINE_LINUX_DEFAULT="rootflags=uquota,pquota"
54+
55+
1. Stop all containers. If you have existing Docker volumes, back up `/var/lib/docker`
56+
57+
```sh
58+
docker stop $(docker ps -a -q)
59+
sudo cp -r /var/lib/docker /var/lib/docker.bk
60+
```
61+
62+
1. Empty the `/var/lib/docker` folder, for mounting
63+
64+
```sh
65+
sudo rm -r /var/lib/docker
66+
sudo mkdir -p /var/lib/docker
67+
```
68+
69+
1. Install a newer version of the Linux kernel (5.19+)
70+
71+
```sh
72+
uname -r
73+
# 5.15.0-67-generic
74+
75+
76+
wget https://raw.githubusercontent.com/pimlie/ubuntu-mainline-kernel.sh/master/ubuntu-mainline-kernel.sh
77+
sudo install ubuntu-mainline-kernel.sh /usr/local/bin/
78+
sudo ubuntu-mainline-kernel.sh -c
79+
sudo ubuntu-mainline-kernel.sh -i
80+
```
81+
82+
> This uses [ubuntu-mainline-kernel](https://github.com/pimlie/ubuntu-mainline-kernel.sh) to safely update.
83+
84+
1. Restart your machine
85+
86+
```sh
87+
sudo reboot
88+
```
89+
90+
1. Ensure Docker is using overlay2/xfs:
91+
92+
```sh
93+
mount | grep '/dev/sdb on /var/lib/docker'
94+
# /dev/sdb on /var/lib/docker type xfs
95+
# (rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,usrquota,prjquota,grpquota)
96+
97+
docker info | egrep "Backing Filesystem|Storage Driver"
98+
# Storage Driver: overlay2
99+
# Backing Filesystem: xfs
100+
```
101+
102+
1. Check your Kernel version
103+
104+
```sh
105+
uname -r
106+
# Must be 5.19+
107+
```
108+
109+
1. Import this template into Coder and create a workspace. Confirm the quota works:
110+
111+
```sh
112+
dd if=/dev/zero of=out bs=4096k
113+
# dd: error writing 'out': No space left on device
114+
# 2535+0 records in
115+
# 2534+0 records out
116+
# 10628366336 bytes (11 GB, 9.9 GiB) copied, 8.64555 s, 1.2 GB/s
117+
```
118+
119+
> This may be slightly different depending on system. Adjust your quota in the template to compensate
120+
121+
1. Measure all quotas on the host with the following command.
122+
123+
```sh
124+
sudo xfs_quota -x -c 'report -h' /var/lib/docker
125+
```

docker-limits/build/Dockerfile

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
FROM ubuntu
2+
3+
RUN apt-get update \
4+
&& apt-get install -y \
5+
curl \
6+
git \
7+
golang \
8+
sudo \
9+
vim \
10+
wget \
11+
&& rm -rf /var/lib/apt/lists/*
12+
13+
ARG USER=coder
14+
RUN useradd --groups sudo --no-create-home --shell /bin/bash ${USER} \
15+
&& echo "${USER} ALL=(ALL) NOPASSWD:ALL" >/etc/sudoers.d/${USER} \
16+
&& chmod 0440 /etc/sudoers.d/${USER}
17+
USER ${USER}
18+
WORKDIR /home/${USER}

docker-limits/main.tf

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
terraform {
2+
required_providers {
3+
coder = {
4+
source = "coder/coder"
5+
version = "~> 0.6.12"
6+
}
7+
docker = {
8+
source = "kreuzwerker/docker"
9+
version = "~> 2.22"
10+
}
11+
}
12+
}
13+
14+
locals {
15+
username = data.coder_workspace.me.owner
16+
}
17+
18+
data "coder_provisioner" "me" {
19+
}
20+
21+
provider "docker" {
22+
}
23+
24+
data "coder_workspace" "me" {
25+
}
26+
27+
resource "coder_agent" "main" {
28+
arch = data.coder_provisioner.me.arch
29+
os = "linux"
30+
31+
login_before_ready = false
32+
startup_script_timeout = 180
33+
startup_script = <<-EOT
34+
set -e
35+
36+
# install and start code-server
37+
curl -fsSL https://code-server.dev/install.sh | sh -s -- --method=standalone --prefix=/tmp/code-server --version 4.8.3
38+
/tmp/code-server/bin/code-server --auth none --port 13337 >/tmp/code-server.log 2>&1 &
39+
EOT
40+
41+
# These environment variables allow you to make Git commits right away after creating a
42+
# workspace. Note that they take precedence over configuration defined in ~/.gitconfig!
43+
# You can remove this block if you'd prefer to configure Git manually or using
44+
# dotfiles. (see docs/dotfiles.md)
45+
env = {
46+
GIT_AUTHOR_NAME = "${data.coder_workspace.me.owner}"
47+
GIT_COMMITTER_NAME = "${data.coder_workspace.me.owner}"
48+
GIT_AUTHOR_EMAIL = "${data.coder_workspace.me.owner_email}"
49+
GIT_COMMITTER_EMAIL = "${data.coder_workspace.me.owner_email}"
50+
}
51+
}
52+
53+
resource "coder_app" "code-server" {
54+
agent_id = coder_agent.main.id
55+
slug = "code-server"
56+
display_name = "code-server"
57+
url = "http://localhost:13337/?folder=/home/${local.username}"
58+
icon = "/icon/code.svg"
59+
subdomain = false
60+
share = "owner"
61+
62+
healthcheck {
63+
url = "http://localhost:13337/healthz"
64+
interval = 5
65+
threshold = 6
66+
}
67+
}
68+
69+
70+
resource "docker_volume" "home_volume" {
71+
name = "coder-${data.coder_workspace.me.id}-home"
72+
# Protect the volume from being deleted due to changes in attributes.
73+
driver_opts = {
74+
size = "10G"
75+
}
76+
lifecycle {
77+
ignore_changes = all
78+
}
79+
# Add labels in Docker to keep track of orphan resources.
80+
labels {
81+
label = "coder.owner"
82+
value = data.coder_workspace.me.owner
83+
}
84+
labels {
85+
label = "coder.owner_id"
86+
value = data.coder_workspace.me.owner_id
87+
}
88+
labels {
89+
label = "coder.workspace_id"
90+
value = data.coder_workspace.me.id
91+
}
92+
# This field becomes outdated if the workspace is renamed but can
93+
# be useful for debugging or cleaning out dangling volumes.
94+
labels {
95+
label = "coder.workspace_name_at_creation"
96+
value = data.coder_workspace.me.name
97+
}
98+
}
99+
100+
101+
resource "docker_image" "main" {
102+
name = "coder-${data.coder_workspace.me.id}"
103+
build {
104+
path = "./build"
105+
build_args = {
106+
USER = local.username
107+
}
108+
}
109+
triggers = {
110+
dir_sha1 = sha1(join("", [for f in fileset(path.module, "build/*") : filesha1(f)]))
111+
}
112+
}
113+
114+
resource "docker_container" "workspace" {
115+
count = data.coder_workspace.me.start_count
116+
image = docker_image.main.name
117+
# Uses lower() to avoid Docker restriction on container names.
118+
name = "coder-${data.coder_workspace.me.owner}-${lower(data.coder_workspace.me.name)}"
119+
# Hostname makes the shell more user friendly: coder@my-workspace:~$
120+
hostname = data.coder_workspace.me.name
121+
# Use the docker gateway if the access URL is 127.0.0.1
122+
entrypoint = ["sh", "-c", replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal")]
123+
env = ["CODER_AGENT_TOKEN=${coder_agent.main.token}"]
124+
125+
# Use sysbox container runtime
126+
runtime = "sysbox-runc"
127+
128+
# Balanced CPU usage
129+
cpu_shares = 1024
130+
131+
# 4 GB memory
132+
memory = 4096
133+
134+
# 10 GB for overlayfs (root filesystem)
135+
storage_opts = {
136+
size = "10G"
137+
}
138+
139+
host {
140+
host = "host.docker.internal"
141+
ip = "host-gateway"
142+
}
143+
volumes {
144+
container_path = "/home/${local.username}"
145+
volume_name = docker_volume.home_volume.name
146+
read_only = false
147+
}
148+
# Add labels in Docker to keep track of orphan resources.
149+
labels {
150+
label = "coder.owner"
151+
value = data.coder_workspace.me.owner
152+
}
153+
labels {
154+
label = "coder.owner_id"
155+
value = data.coder_workspace.me.owner_id
156+
}
157+
labels {
158+
label = "coder.workspace_id"
159+
value = data.coder_workspace.me.id
160+
}
161+
labels {
162+
label = "coder.workspace_name"
163+
value = data.coder_workspace.me.name
164+
}
165+
}

0 commit comments

Comments
 (0)