Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.sh text eol=lf
11 changes: 11 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"

- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
15 changes: 0 additions & 15 deletions .github/workflows/clabot.yml

This file was deleted.

19 changes: 5 additions & 14 deletions .github/workflows/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,13 @@ on:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
build:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- name: Run containerd-driver integration tests
run: |
# Remove older version of golang.
sudo rm -f /usr/bin/go
# Install golang-1.17
export PATH=$PATH:/usr/local/go/bin
curl -s -L -o go1.17.linux-amd64.tar.gz https://dl.google.com/go/go1.17.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.17.linux-amd64.tar.gz
sudo chmod +x /usr/local/go
rm -f go1.17.linux-amd64.tar.gz
mkdir -p /home/runner/go/src/github.com/Roblox
ln -s /home/runner/work/nomad-driver-containerd/nomad-driver-containerd /home/runner/go/src/github.com/Roblox/nomad-driver-containerd
cd /home/runner/go/src/github.com/Roblox/nomad-driver-containerd
sudo modprobe bridge
mkdir -p /home/runner/go/src/github.com/hashistack4u
ln -s /home/runner/work/nomad-driver-containerd/nomad-driver-containerd /home/runner/go/src/github.com/hashistack4u/nomad-driver-containerd
cd /home/runner/go/src/github.com/hashistack4u/nomad-driver-containerd
make test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.vagrant/
/containerd-driver
/containerd-driver.exe
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ clean:
.PHONY: build
build:
$(GOLANG) build -o $(BINARY) .
GOOS=windows $(GOLANG) build -o $(BINARY).exe .

.PHONY: test
test:
Expand Down
137 changes: 78 additions & 59 deletions README.md

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions Vagrantfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ VAGRANTFILE_API_VERSION = "2"
# Create box
Vagrant.configure("2") do |config|
config.vm.define "containerd-linux"
config.vm.box = "hashicorp/bionic64"
config.vm.box = "generic/ubuntu2204"
config.vm.provider "libvirt" do |v, override|
override.vm.box = "generic/debian10"
override.vm.synced_folder ".", "/home/vagrant/go/src/github.com/Roblox/nomad-driver-containerd", type: "nfs", nfs_version: 4, nfs_udp: false
override.vm.synced_folder ".", "/home/vagrant/go/src/github.com/hashistack4u/nomad-driver-containerd", type: "nfs", nfs_version: 4, nfs_udp: false
end
config.vm.synced_folder ".", "/home/vagrant/go/src/github.com/Roblox/nomad-driver-containerd"
config.ssh.extra_args = ["-t", "cd /home/vagrant/go/src/github.com/Roblox/nomad-driver-containerd; bash --login"]
config.vm.synced_folder ".", "/home/vagrant/go/src/github.com/hashistack4u/nomad-driver-containerd"
config.ssh.extra_args = ["-t", "cd /home/vagrant/go/src/github.com/hashistack4u/nomad-driver-containerd; bash --login"]
config.vm.network "forwarded_port", guest: 4646, host: 4646, host_ip: "127.0.0.1"
config.vm.provider "virtualbox" do |vb|
vb.name = "containerd-linux"
Expand All @@ -20,10 +20,10 @@ Vagrant.configure("2") do |config|
end
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y unzip gcc runc jq
apt-get install -y unzip gcc runc jq make
echo "export GOPATH=/home/vagrant/go" >> /home/vagrant/.bashrc
echo "export PATH=$PATH:/usr/local/go/bin" >> /home/vagrant/.bashrc
echo "export CONTAINERD_NAMESPACE=nomad" >> /home/vagrant/.bashrc
echo "export CONTAINERD_NAMESPACE=nomad.slice" >> /home/vagrant/.bashrc
source /home/vagrant/.bashrc
# without keeping HOME env, 'sudo make test' will try to find files under /root/go/
echo "Defaults env_keep += HOME" | sudo tee /etc/sudoers.d/keep_home
Expand Down Expand Up @@ -65,7 +65,7 @@ Vagrant.configure("2") do |config|
mkdir -p /tmp/host_volume/s1
# Run setup
cd /home/vagrant/go/src/github.com/Roblox/nomad-driver-containerd/vagrant
cd /home/vagrant/go/src/github.com/hashistack4u/nomad-driver-containerd/vagrant
./setup.sh
SHELL
end
60 changes: 49 additions & 11 deletions containerd/containerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ import (
"strings"
"time"

etchosts "github.com/Roblox/nomad-driver-containerd/etchosts"
"github.com/containerd/containerd"
"github.com/containerd/containerd/cio"
"github.com/containerd/containerd/containers"
"github.com/containerd/containerd/contrib/seccomp"
"github.com/containerd/containerd/oci"
refdocker "github.com/containerd/containerd/reference/docker"
remotesdocker "github.com/containerd/containerd/remotes/docker"
"github.com/docker/go-units"
etchosts "github.com/hashistack4u/nomad-driver-containerd/etchosts"
specs "github.com/opencontainers/runtime-spec/specs-go"
)

Expand Down Expand Up @@ -93,10 +94,31 @@ func withResolver(creds CredentialsOpt) containerd.RemoteOpt {
return containerd.WithResolver(resolver)
}

func withFileLimit(maxOpenFiles uint64) oci.SpecOpts {
return func(_ context.Context, _ oci.Client, _ *containers.Container, spec *oci.Spec) error {
newRlimits := []specs.POSIXRlimit{{
Type: "RLIMIT_NOFILE",
Hard: maxOpenFiles,
Soft: maxOpenFiles,
}}

// Copy existing rlimits excluding previous RLIMIT_NOFILE
for _, rlimit := range spec.Process.Rlimits {
if rlimit.Type != "RLIMIT_NOFILE" {
newRlimits = append(newRlimits, rlimit)
}
}

spec.Process.Rlimits = newRlimits

return nil
}
}

func (d *Driver) pullImage(imageName, imagePullTimeout string, auth *RegistryAuth) (containerd.Image, error) {
pullTimeout, err := time.ParseDuration(imagePullTimeout)
if err != nil {
return nil, fmt.Errorf("Failed to parse image_pull_timeout: %v", err)
return nil, fmt.Errorf("failed to parse image_pull_timeout: %v", err)
}

ctxWithTimeout, cancel := context.WithTimeout(d.ctxContainerd, pullTimeout)
Expand All @@ -117,7 +139,7 @@ func (d *Driver) pullImage(imageName, imagePullTimeout string, auth *RegistryAut

func (d *Driver) createContainer(containerConfig *ContainerConfig, config *TaskConfig) (containerd.Container, error) {
if config.Command != "" && config.Entrypoint != nil {
return nil, fmt.Errorf("Both command and entrypoint are set. Only one of them needs to be set.")
return nil, fmt.Errorf("both command and entrypoint are set. Only one of them needs to be set")
}

// Entrypoint or Command set by the user, to override entrypoint or cmd defined in the image.
Expand Down Expand Up @@ -146,7 +168,7 @@ func (d *Driver) createContainer(containerConfig *ContainerConfig, config *TaskC
}

if !d.config.AllowPrivileged && config.Privileged {
return nil, fmt.Errorf("Running privileged jobs are not allowed. Set allow_privileged to true in plugin config to allow running privileged jobs.")
return nil, fmt.Errorf("running privileged jobs are not allowed. Set allow_privileged to true in plugin config to allow running privileged jobs")
}

// Enable privileged mode.
Expand All @@ -161,17 +183,22 @@ func (d *Driver) createContainer(containerConfig *ContainerConfig, config *TaskC

if config.PidMode != "" {
if strings.ToLower(config.PidMode) != "host" {
return nil, fmt.Errorf("Invalid pid_mode. Set pid_mode=host to enable host pid namespace.")
return nil, fmt.Errorf("invalid pid_mode. Set pid_mode=host to enable host pid namespace")
} else {
opts = append(opts, oci.WithHostNamespace(specs.PIDNamespace))
}
}

// Set the resource limit for open file descriptors
if config.FileLimit > 0 {
opts = append(opts, withFileLimit(uint64(config.FileLimit)))
}

// Size of /dev/shm
if len(config.ShmSize) > 0 {
shmBytes, err := units.RAMInBytes(config.ShmSize)
if err != nil {
return nil, fmt.Errorf("Error in setting shm_size: %v", err)
return nil, fmt.Errorf("error in setting shm_size: %v", err)
}
opts = append(opts, oci.WithDevShmSize(shmBytes/1024))
}
Expand All @@ -182,7 +209,7 @@ func (d *Driver) createContainer(containerConfig *ContainerConfig, config *TaskC
}

if !config.Seccomp && config.SeccompProfile != "" {
return nil, fmt.Errorf("seccomp must be set to true, if using a custom seccomp_profile.")
return nil, fmt.Errorf("seccomp must be set to true, if using a custom seccomp_profile")
}

// Enable default (or custom) seccomp profile.
Expand Down Expand Up @@ -217,6 +244,18 @@ func (d *Driver) createContainer(containerConfig *ContainerConfig, config *TaskC
opts = append(opts, oci.WithDroppedCapabilities(config.CapDrop))
}

// This translates to docker create/run --cpuset-cpus option.
// --cpuset-cpus limit the specific CPUs or cores a container can use.
if config.CPUSetCPUs != "" {
opts = append(opts, oci.WithCPUs(config.CPUSetCPUs))
}

// --cpuset-mems is the list of memory nodes on which processes
// in this cpuset are allowed to allocate memory.
if config.CPUSetMEMs != "" {
opts = append(opts, oci.WithCPUsMems(config.CPUSetMEMs))
}

// Set current working directory (cwd).
if config.Cwd != "" {
opts = append(opts, oci.WithProcessCwd(config.Cwd))
Expand Down Expand Up @@ -249,11 +288,11 @@ func (d *Driver) createContainer(containerConfig *ContainerConfig, config *TaskC
mounts := make([]specs.Mount, 0)
for _, mount := range config.Mounts {
if (mount.Type == "bind" || mount.Type == "volume") && len(mount.Options) <= 0 {
return nil, fmt.Errorf("Options cannot be empty for mount type: %s. You need to atleast pass rbind and ro.", mount.Type)
return nil, fmt.Errorf("options cannot be empty for mount type: %s. You need to atleast pass rbind and ro", mount.Type)
}

// Allow paths relative to $NOMAD_TASK_DIR.
// More details: https://github.com/Roblox/nomad-driver-containerd/issues/116#issuecomment-983171458
// More details: https://github.com/hashistack4u/nomad-driver-containerd/issues/116#issuecomment-983171458
if mount.Type == "bind" && strings.HasPrefix(mount.Source, "local") {
mount.Source = containerConfig.TaskDirSrc + mount.Source[5:]
}
Expand All @@ -264,8 +303,7 @@ func (d *Driver) createContainer(containerConfig *ContainerConfig, config *TaskC

// Setup host DNS (/etc/resolv.conf) into the container.
if config.HostDNS {
dnsMount := buildMountpoint("bind", "/etc/resolv.conf", "/etc/resolv.conf", []string{"rbind", "ro"})
mounts = append(mounts, dnsMount)
opts = append(opts, oci.WithHostResolvconf)
}

// Setup "/secrets" (NOMAD_SECRETS_DIR) in the container.
Expand Down
Loading
Loading