mirror of https://github.com/docker/docs.git
Remove LXC support.
The LXC driver was deprecated in Docker 1.8. Following the deprecation rules, we can remove a deprecated feature after two major releases. LXC won't be supported anymore starting on Docker 1.10. Signed-off-by: David Calavera <david.calavera@gmail.com>
This commit is contained in:
parent
b2f14f9bec
commit
3b5fac462d
10
Dockerfile
10
Dockerfile
|
@ -72,16 +72,6 @@ RUN cd /usr/local/lvm2 \
|
||||||
&& make install_device-mapper
|
&& make install_device-mapper
|
||||||
# see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
# see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||||
|
|
||||||
# Install lxc
|
|
||||||
ENV LXC_VERSION 1.1.2
|
|
||||||
RUN mkdir -p /usr/src/lxc \
|
|
||||||
&& curl -sSL https://linuxcontainers.org/downloads/lxc/lxc-${LXC_VERSION}.tar.gz | tar -v -C /usr/src/lxc/ -xz --strip-components=1
|
|
||||||
RUN cd /usr/src/lxc \
|
|
||||||
&& ./configure \
|
|
||||||
&& make \
|
|
||||||
&& make install \
|
|
||||||
&& ldconfig
|
|
||||||
|
|
||||||
# Install Go
|
# Install Go
|
||||||
ENV GO_VERSION 1.5.1
|
ENV GO_VERSION 1.5.1
|
||||||
RUN curl -sSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar -v -C /usr/local -xz
|
RUN curl -sSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar -v -C /usr/local -xz
|
||||||
|
|
|
@ -39,16 +39,6 @@ RUN cd /usr/local/lvm2 \
|
||||||
&& make install_device-mapper
|
&& make install_device-mapper
|
||||||
# see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
# see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||||
|
|
||||||
# Install lxc
|
|
||||||
ENV LXC_VERSION 1.1.2
|
|
||||||
RUN mkdir -p /usr/src/lxc \
|
|
||||||
&& curl -sSL https://linuxcontainers.org/downloads/lxc/lxc-${LXC_VERSION}.tar.gz | tar -v -C /usr/src/lxc/ -xz --strip-components=1
|
|
||||||
RUN cd /usr/src/lxc \
|
|
||||||
&& ./configure \
|
|
||||||
&& make \
|
|
||||||
&& make install \
|
|
||||||
&& ldconfig
|
|
||||||
|
|
||||||
ENV GOPATH /go:/go/src/github.com/docker/docker/vendor
|
ENV GOPATH /go:/go/src/github.com/docker/docker/vendor
|
||||||
|
|
||||||
# Get the "docker-py" source so we can run their integration tests
|
# Get the "docker-py" source so we can run their integration tests
|
||||||
|
|
|
@ -26,7 +26,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
xz-utils \
|
xz-utils \
|
||||||
\
|
\
|
||||||
aufs-tools \
|
aufs-tools \
|
||||||
lxc \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
ENV AUTO_GOPATH 1
|
ENV AUTO_GOPATH 1
|
||||||
|
|
|
@ -40,7 +40,6 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
||||||
libapparmor-dev \
|
libapparmor-dev \
|
||||||
libcap-dev \
|
libcap-dev \
|
||||||
libsqlite3-dev \
|
libsqlite3-dev \
|
||||||
lxc=1.0* \
|
|
||||||
mercurial \
|
mercurial \
|
||||||
pandoc \
|
pandoc \
|
||||||
parallel \
|
parallel \
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
(from "ubuntu:14.04")
|
(from "ubuntu:14.04")
|
||||||
(maintainer "Tianon Gravi <admwiggin@gmail.com> (@tianon)")
|
(maintainer "Tianon Gravi <admwiggin@gmail.com> (@tianon)")
|
||||||
(run "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -yq \tapt-utils \taufs-tools \tautomake \tbtrfs-tools \tbuild-essential \tcurl \tdpkg-sig \tgit \tiptables \tlibapparmor-dev \tlibcap-dev \tlibsqlite3-dev \tlxc=1.0* \tmercurial \tpandoc \tparallel \treprepro \truby1.9.1 \truby1.9.1-dev \ts3cmd=1.1.0* \t--no-install-recommends")
|
(run "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -yq \tapt-utils \taufs-tools \tautomake \tbtrfs-tools \tbuild-essential \tcurl \tdpkg-sig \tgit \tiptables \tlibapparmor-dev \tlibcap-dev \tlibsqlite3-dev \tmercurial \tpandoc \tparallel \treprepro \truby1.9.1 \truby1.9.1-dev \ts3cmd=1.1.0* \t--no-install-recommends")
|
||||||
(run "git clone --no-checkout https://git.fedorahosted.org/git/lvm2.git /usr/local/lvm2 && cd /usr/local/lvm2 && git checkout -q v2_02_103")
|
(run "git clone --no-checkout https://git.fedorahosted.org/git/lvm2.git /usr/local/lvm2 && cd /usr/local/lvm2 && git checkout -q v2_02_103")
|
||||||
(run "cd /usr/local/lvm2 && ./configure --enable-static_link && make device-mapper && make install_device-mapper")
|
(run "cd /usr/local/lvm2 && ./configure --enable-static_link && make device-mapper && make install_device-mapper")
|
||||||
(run "curl -sSL https://golang.org/dl/go1.3.src.tar.gz | tar -v -C /usr/local -xz")
|
(run "curl -sSL https://golang.org/dl/go1.3.src.tar.gz | tar -v -C /usr/local -xz")
|
||||||
|
|
|
@ -1379,7 +1379,6 @@ _docker_run() {
|
||||||
--link
|
--link
|
||||||
--log-driver
|
--log-driver
|
||||||
--log-opt
|
--log-opt
|
||||||
--lxc-conf
|
|
||||||
--mac-address
|
--mac-address
|
||||||
--memory -m
|
--memory -m
|
||||||
--memory-swap
|
--memory-swap
|
||||||
|
|
|
@ -135,7 +135,6 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l help -d 'Pri
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s i -l interactive -d 'Keep STDIN open even if not attached'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s i -l interactive -d 'Keep STDIN open even if not attached'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l ipc -d 'Default is to create a private IPC namespace (POSIX SysV IPC) for the container'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l ipc -d 'Default is to create a private IPC namespace (POSIX SysV IPC) for the container'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l link -d 'Add link to another container in the form of <name|id>:alias'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l link -d 'Add link to another container in the form of <name|id>:alias'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l lxc-conf -d '(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"'
|
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s m -l memory -d 'Memory limit (format: <number>[<unit>], where unit = b, k, m or g)'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s m -l memory -d 'Memory limit (format: <number>[<unit>], where unit = b, k, m or g)'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l mac-address -d 'Container MAC address (e.g. 92:d0:c6:0a:29:33)'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l mac-address -d 'Container MAC address (e.g. 92:d0:c6:0a:29:33)'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number>[<unit>], where unit = b, k, m or g)"
|
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number>[<unit>], where unit = b, k, m or g)"
|
||||||
|
@ -324,7 +323,6 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l help -d 'Print
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s i -l interactive -d 'Keep STDIN open even if not attached'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s i -l interactive -d 'Keep STDIN open even if not attached'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l ipc -d 'Default is to create a private IPC namespace (POSIX SysV IPC) for the container'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l ipc -d 'Default is to create a private IPC namespace (POSIX SysV IPC) for the container'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l link -d 'Add link to another container in the form of <name|id>:alias'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l link -d 'Add link to another container in the form of <name|id>:alias'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l lxc-conf -d '(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"'
|
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s m -l memory -d 'Memory limit (format: <number>[<unit>], where unit = b, k, m or g)'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s m -l memory -d 'Memory limit (format: <number>[<unit>], where unit = b, k, m or g)'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l mac-address -d 'Container MAC address (e.g. 92:d0:c6:0a:29:33)'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l mac-address -d 'Container MAC address (e.g. 92:d0:c6:0a:29:33)'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number>[<unit>], where unit = b, k, m or g)"
|
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number>[<unit>], where unit = b, k, m or g)"
|
||||||
|
|
|
@ -438,7 +438,6 @@ __docker_subcommand() {
|
||||||
"($help)*"{-l=,--label=}"[Set meta data on a container]:label: "
|
"($help)*"{-l=,--label=}"[Set meta data on a container]:label: "
|
||||||
"($help)--log-driver=[Default driver for container logs]:Logging driver:(json-file syslog journald gelf fluentd awslogs splunk none)"
|
"($help)--log-driver=[Default driver for container logs]:Logging driver:(json-file syslog journald gelf fluentd awslogs splunk none)"
|
||||||
"($help)*--log-opt=[Log driver specific options]:log driver options: "
|
"($help)*--log-opt=[Log driver specific options]:log driver options: "
|
||||||
"($help)*--lxc-conf=[Add custom lxc options]:lxc options: "
|
|
||||||
"($help)--mac-address=[Container MAC address]:MAC address: "
|
"($help)--mac-address=[Container MAC address]:MAC address: "
|
||||||
"($help)--name=[Container name]:name: "
|
"($help)--name=[Container name]:name: "
|
||||||
"($help)--net=[Connect a container to a network]:network mode:(bridge none container host)"
|
"($help)--net=[Connect a container to a network]:network mode:(bridge none container host)"
|
||||||
|
@ -541,7 +540,7 @@ __docker_subcommand() {
|
||||||
"($help)*--dns-opt=[DNS options to use]:DNS option: " \
|
"($help)*--dns-opt=[DNS options to use]:DNS option: " \
|
||||||
"($help)*--default-ulimit=[Set default ulimit settings for containers]:ulimit: " \
|
"($help)*--default-ulimit=[Set default ulimit settings for containers]:ulimit: " \
|
||||||
"($help)--disable-legacy-registry[Do not contact legacy registries]" \
|
"($help)--disable-legacy-registry[Do not contact legacy registries]" \
|
||||||
"($help -e --exec-driver)"{-e=,--exec-driver=}"[Exec driver to use]:driver:(native lxc windows)" \
|
"($help -e --exec-driver)"{-e=,--exec-driver=}"[Exec driver to use]:driver:(native windows)" \
|
||||||
"($help)*--exec-opt=[Set exec driver options]:exec driver options: " \
|
"($help)*--exec-opt=[Set exec driver options]:exec driver options: " \
|
||||||
"($help)--exec-root=[Root of the Docker execdriver]:path:_directories" \
|
"($help)--exec-root=[Root of the Docker execdriver]:path:_directories" \
|
||||||
"($help)--fixed-cidr=[IPv4 subnet for fixed IPs]:IPv4 subnet: " \
|
"($help)--fixed-cidr=[IPv4 subnet for fixed IPs]:IPv4 subnet: " \
|
||||||
|
|
|
@ -14,10 +14,6 @@
|
||||||
/var/run/docker\.sock -s gen_context(system_u:object_r:docker_var_run_t,s0)
|
/var/run/docker\.sock -s gen_context(system_u:object_r:docker_var_run_t,s0)
|
||||||
/var/run/docker-client(/.*)? gen_context(system_u:object_r:docker_var_run_t,s0)
|
/var/run/docker-client(/.*)? gen_context(system_u:object_r:docker_var_run_t,s0)
|
||||||
|
|
||||||
/var/lock/lxc(/.*)? gen_context(system_u:object_r:docker_lock_t,s0)
|
|
||||||
|
|
||||||
/var/log/lxc(/.*)? gen_context(system_u:object_r:docker_log_t,s0)
|
|
||||||
|
|
||||||
/var/lib/docker/init(/.*)? gen_context(system_u:object_r:docker_share_t,s0)
|
/var/lib/docker/init(/.*)? gen_context(system_u:object_r:docker_share_t,s0)
|
||||||
/var/lib/docker/containers/.*/hosts gen_context(system_u:object_r:docker_share_t,s0)
|
/var/lib/docker/containers/.*/hosts gen_context(system_u:object_r:docker_share_t,s0)
|
||||||
/var/lib/docker/containers/.*/hostname gen_context(system_u:object_r:docker_share_t,s0)
|
/var/lib/docker/containers/.*/hostname gen_context(system_u:object_r:docker_share_t,s0)
|
||||||
|
|
|
@ -292,7 +292,6 @@ interface(`docker_filetrans_named_content',`
|
||||||
files_pid_filetrans($1, docker_var_run_t, file, "docker.pid")
|
files_pid_filetrans($1, docker_var_run_t, file, "docker.pid")
|
||||||
files_pid_filetrans($1, docker_var_run_t, sock_file, "docker.sock")
|
files_pid_filetrans($1, docker_var_run_t, sock_file, "docker.sock")
|
||||||
files_pid_filetrans($1, docker_var_run_t, dir, "docker-client")
|
files_pid_filetrans($1, docker_var_run_t, dir, "docker-client")
|
||||||
logging_log_filetrans($1, docker_log_t, dir, "lxc")
|
|
||||||
files_var_lib_filetrans($1, docker_var_lib_t, dir, "docker")
|
files_var_lib_filetrans($1, docker_var_lib_t, dir, "docker")
|
||||||
filetrans_pattern($1, docker_var_lib_t, docker_share_t, file, "config.env")
|
filetrans_pattern($1, docker_var_lib_t, docker_share_t, file, "config.env")
|
||||||
filetrans_pattern($1, docker_var_lib_t, docker_share_t, file, "hosts")
|
filetrans_pattern($1, docker_var_lib_t, docker_share_t, file, "hosts")
|
||||||
|
@ -406,11 +405,6 @@ interface(`staff_stub',`
|
||||||
type staff_t;
|
type staff_t;
|
||||||
')
|
')
|
||||||
')
|
')
|
||||||
interface(`virt_stub_lxc',`
|
|
||||||
gen_require(`
|
|
||||||
type virtd_lxc_t;
|
|
||||||
')
|
|
||||||
')
|
|
||||||
interface(`virt_stub_svirt_sandbox_domain',`
|
interface(`virt_stub_svirt_sandbox_domain',`
|
||||||
gen_require(`
|
gen_require(`
|
||||||
attribute svirt_sandbox_domain;
|
attribute svirt_sandbox_domain;
|
||||||
|
|
|
@ -90,7 +90,6 @@ files_etc_filetrans(docker_t, docker_config_t, dir, "docker")
|
||||||
|
|
||||||
manage_dirs_pattern(docker_t, docker_lock_t, docker_lock_t)
|
manage_dirs_pattern(docker_t, docker_lock_t, docker_lock_t)
|
||||||
manage_files_pattern(docker_t, docker_lock_t, docker_lock_t)
|
manage_files_pattern(docker_t, docker_lock_t, docker_lock_t)
|
||||||
files_lock_filetrans(docker_t, docker_lock_t, { dir file }, "lxc")
|
|
||||||
|
|
||||||
manage_dirs_pattern(docker_t, docker_log_t, docker_log_t)
|
manage_dirs_pattern(docker_t, docker_log_t, docker_log_t)
|
||||||
manage_files_pattern(docker_t, docker_log_t, docker_log_t)
|
manage_files_pattern(docker_t, docker_log_t, docker_log_t)
|
||||||
|
@ -213,10 +212,6 @@ optional_policy(`
|
||||||
openvswitch_stream_connect(docker_t)
|
openvswitch_stream_connect(docker_t)
|
||||||
')
|
')
|
||||||
|
|
||||||
#
|
|
||||||
# lxc rules
|
|
||||||
#
|
|
||||||
|
|
||||||
allow docker_t self:capability { dac_override setgid setpcap setuid sys_admin sys_boot sys_chroot sys_ptrace };
|
allow docker_t self:capability { dac_override setgid setpcap setuid sys_admin sys_boot sys_chroot sys_ptrace };
|
||||||
|
|
||||||
allow docker_t self:process { getcap setcap setexec setpgid setsched signal_perms };
|
allow docker_t self:process { getcap setcap setexec setpgid setsched signal_perms };
|
||||||
|
@ -317,7 +312,6 @@ optional_policy(`
|
||||||
virt_exec_sandbox_files(docker_t)
|
virt_exec_sandbox_files(docker_t)
|
||||||
virt_manage_sandbox_files(docker_t)
|
virt_manage_sandbox_files(docker_t)
|
||||||
virt_relabel_sandbox_filesystem(docker_t)
|
virt_relabel_sandbox_filesystem(docker_t)
|
||||||
# for lxc
|
|
||||||
virt_transition_svirt_sandbox(docker_t, system_r)
|
virt_transition_svirt_sandbox(docker_t, system_r)
|
||||||
virt_mounton_sandbox_file(docker_t)
|
virt_mounton_sandbox_file(docker_t)
|
||||||
# virt_attach_sandbox_tun_iface(docker_t)
|
# virt_attach_sandbox_tun_iface(docker_t)
|
||||||
|
@ -387,11 +381,6 @@ optional_policy(`
|
||||||
docker_exec(staff_t)
|
docker_exec(staff_t)
|
||||||
')
|
')
|
||||||
|
|
||||||
optional_policy(`
|
|
||||||
virt_stub_lxc()
|
|
||||||
docker_exec_lib(virtd_lxc_t)
|
|
||||||
')
|
|
||||||
|
|
||||||
optional_policy(`
|
optional_policy(`
|
||||||
virt_stub_svirt_sandbox_domain()
|
virt_stub_svirt_sandbox_domain()
|
||||||
virt_stub_svirt_sandbox_file()
|
virt_stub_svirt_sandbox_file()
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
#!/usr/bin/perl
|
|
||||||
#
|
|
||||||
# A simple helper script to help people build seccomp profiles for
|
|
||||||
# Docker/LXC. The goal is mostly to reduce the attack surface to the
|
|
||||||
# kernel, by restricting access to rarely used, recently added or not used
|
|
||||||
# syscalls.
|
|
||||||
#
|
|
||||||
# This script processes one or more files which contain the list of system
|
|
||||||
# calls to be allowed. See mkseccomp.sample for more information how you
|
|
||||||
# can configure the list of syscalls. When run, this script produces output
|
|
||||||
# which, when stored in a file, can be passed to docker as follows:
|
|
||||||
#
|
|
||||||
# docker run --lxc-conf="lxc.seccomp=$file" <rest of arguments>
|
|
||||||
#
|
|
||||||
# The included sample file shows how to cut about a quarter of all syscalls,
|
|
||||||
# which affecting most applications.
|
|
||||||
#
|
|
||||||
# For specific situations it is possible to reduce the list further. By
|
|
||||||
# reducing the list to just those syscalls required by a certain application
|
|
||||||
# you can make it difficult for unknown/unexpected code to run.
|
|
||||||
#
|
|
||||||
# Run this script as follows:
|
|
||||||
#
|
|
||||||
# ./mkseccomp.pl < mkseccomp.sample >syscalls.list
|
|
||||||
# or
|
|
||||||
# ./mkseccomp.pl mkseccomp.sample >syscalls.list
|
|
||||||
#
|
|
||||||
# Multiple files can be specified, in which case the lists of syscalls are
|
|
||||||
# combined.
|
|
||||||
#
|
|
||||||
# By Martijn van Oosterhout <kleptog@svana.org> Nov 2013
|
|
||||||
|
|
||||||
# How it works:
|
|
||||||
#
|
|
||||||
# This program basically spawns two processes to form a chain like:
|
|
||||||
#
|
|
||||||
# <process data section to prefix __NR_> | cpp | <add header and filter unknown syscalls>
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
if( -t ) {
|
|
||||||
print STDERR "Helper script to make seccomp filters for Docker/LXC.\n";
|
|
||||||
print STDERR "Usage: mkseccomp.pl < [files...]\n";
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $pid = open(my $in, "-|") // die "Couldn't fork1 ($!)\n";
|
|
||||||
|
|
||||||
if($pid == 0) { # Child
|
|
||||||
$pid = open(my $out, "|-") // die "Couldn't fork2 ($!)\n";
|
|
||||||
|
|
||||||
if($pid == 0) { # Child, which execs cpp
|
|
||||||
exec "cpp" or die "Couldn't exec cpp ($!)\n";
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Process the DATA section and output to cpp
|
|
||||||
print $out "#include <sys/syscall.h>\n";
|
|
||||||
while(<>) {
|
|
||||||
if(/^\w/) {
|
|
||||||
print $out "__NR_$_";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close $out;
|
|
||||||
exit 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# Print header and then process output from cpp.
|
|
||||||
print "1\n";
|
|
||||||
print "whitelist\n";
|
|
||||||
|
|
||||||
while(<$in>) {
|
|
||||||
print if( /^[0-9]/ );
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,444 +0,0 @@
|
||||||
/* This sample file is an example for mkseccomp.pl to produce a seccomp file
|
|
||||||
* which restricts syscalls that are only useful for an admin but allows the
|
|
||||||
* vast majority of normal userspace programs to run normally.
|
|
||||||
*
|
|
||||||
* The format of this file is one line per syscall. This is then processed
|
|
||||||
* and passed to 'cpp' to convert the names to numbers using whatever is
|
|
||||||
* correct for your platform. As such C-style comments are permitted. Note
|
|
||||||
* this also means that C preprocessor macros are also allowed. So it is
|
|
||||||
* possible to create groups surrounded by #ifdef/#endif and control their
|
|
||||||
* inclusion via #define (not #include).
|
|
||||||
*
|
|
||||||
* Syscalls that don't exist on your architecture are silently filtered out.
|
|
||||||
* Syscalls marked with (*) are required for a container to spawn a bash
|
|
||||||
* shell successfully (not necessarily full featured). Listing the same
|
|
||||||
* syscall multiple times is no problem.
|
|
||||||
*
|
|
||||||
* If you want to make a list specifically for one application the easiest
|
|
||||||
* way is to run the application under strace, like so:
|
|
||||||
*
|
|
||||||
* $ strace -f -q -c -o strace.out application args...
|
|
||||||
*
|
|
||||||
* Once you have a reasonable sample of the execution of the program, exit
|
|
||||||
* it. The file strace.out will have a summary of the syscalls used. Copy
|
|
||||||
* that list into this file, comment out everything else except the starred
|
|
||||||
* syscalls (which you need for the container to start) and you're done.
|
|
||||||
*
|
|
||||||
* To get the list of syscalls from the strace output this works well for
|
|
||||||
* me
|
|
||||||
*
|
|
||||||
* $ cut -c52 < strace.out
|
|
||||||
*
|
|
||||||
* This sample list was compiled as a combination of all the syscalls
|
|
||||||
* available on i386 and amd64 on Ubuntu Precise, as such it may not contain
|
|
||||||
* everything and not everything may be relevant for your system. This
|
|
||||||
* shouldn't be a problem.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Filesystem/File descriptor related
|
|
||||||
access // (*)
|
|
||||||
chdir // (*)
|
|
||||||
chmod
|
|
||||||
chown
|
|
||||||
chown32
|
|
||||||
close // (*)
|
|
||||||
creat
|
|
||||||
dup // (*)
|
|
||||||
dup2 // (*)
|
|
||||||
dup3
|
|
||||||
epoll_create
|
|
||||||
epoll_create1
|
|
||||||
epoll_ctl
|
|
||||||
epoll_ctl_old
|
|
||||||
epoll_pwait
|
|
||||||
epoll_wait
|
|
||||||
epoll_wait_old
|
|
||||||
eventfd
|
|
||||||
eventfd2
|
|
||||||
faccessat // (*)
|
|
||||||
fadvise64
|
|
||||||
fadvise64_64
|
|
||||||
fallocate
|
|
||||||
fanotify_init
|
|
||||||
fanotify_mark
|
|
||||||
ioctl // (*)
|
|
||||||
fchdir
|
|
||||||
fchmod
|
|
||||||
fchmodat
|
|
||||||
fchown
|
|
||||||
fchown32
|
|
||||||
fchownat
|
|
||||||
fcntl // (*)
|
|
||||||
fcntl64
|
|
||||||
fdatasync
|
|
||||||
fgetxattr
|
|
||||||
flistxattr
|
|
||||||
flock
|
|
||||||
fremovexattr
|
|
||||||
fsetxattr
|
|
||||||
fstat // (*)
|
|
||||||
fstat64
|
|
||||||
fstatat64
|
|
||||||
fstatfs
|
|
||||||
fstatfs64
|
|
||||||
fsync
|
|
||||||
ftruncate
|
|
||||||
ftruncate64
|
|
||||||
getcwd // (*)
|
|
||||||
getdents // (*)
|
|
||||||
getdents64
|
|
||||||
getxattr
|
|
||||||
inotify_add_watch
|
|
||||||
inotify_init
|
|
||||||
inotify_init1
|
|
||||||
inotify_rm_watch
|
|
||||||
io_cancel
|
|
||||||
io_destroy
|
|
||||||
io_getevents
|
|
||||||
io_setup
|
|
||||||
io_submit
|
|
||||||
lchown
|
|
||||||
lchown32
|
|
||||||
lgetxattr
|
|
||||||
link
|
|
||||||
linkat
|
|
||||||
listxattr
|
|
||||||
llistxattr
|
|
||||||
llseek
|
|
||||||
_llseek
|
|
||||||
lremovexattr
|
|
||||||
lseek // (*)
|
|
||||||
lsetxattr
|
|
||||||
lstat
|
|
||||||
lstat64
|
|
||||||
mkdir
|
|
||||||
mkdirat
|
|
||||||
mknod
|
|
||||||
mknodat
|
|
||||||
newfstatat
|
|
||||||
_newselect
|
|
||||||
oldfstat
|
|
||||||
oldlstat
|
|
||||||
oldolduname
|
|
||||||
oldstat
|
|
||||||
olduname
|
|
||||||
oldwait4
|
|
||||||
open // (*)
|
|
||||||
openat // (*)
|
|
||||||
pipe // (*)
|
|
||||||
pipe2
|
|
||||||
poll
|
|
||||||
ppoll
|
|
||||||
pread64
|
|
||||||
preadv
|
|
||||||
futimesat
|
|
||||||
pselect6
|
|
||||||
pwrite64
|
|
||||||
pwritev
|
|
||||||
read // (*)
|
|
||||||
readahead
|
|
||||||
readdir
|
|
||||||
readlink
|
|
||||||
readlinkat
|
|
||||||
readv
|
|
||||||
removexattr
|
|
||||||
rename
|
|
||||||
renameat
|
|
||||||
rmdir
|
|
||||||
select
|
|
||||||
sendfile
|
|
||||||
sendfile64
|
|
||||||
setxattr
|
|
||||||
splice
|
|
||||||
stat // (*)
|
|
||||||
stat64
|
|
||||||
statfs // (*)
|
|
||||||
statfs64
|
|
||||||
symlink
|
|
||||||
symlinkat
|
|
||||||
sync
|
|
||||||
sync_file_range
|
|
||||||
sync_file_range2
|
|
||||||
syncfs
|
|
||||||
tee
|
|
||||||
truncate
|
|
||||||
truncate64
|
|
||||||
umask
|
|
||||||
unlink
|
|
||||||
unlinkat
|
|
||||||
ustat
|
|
||||||
utime
|
|
||||||
utimensat
|
|
||||||
utimes
|
|
||||||
write // (*)
|
|
||||||
writev
|
|
||||||
|
|
||||||
// Network related
|
|
||||||
accept
|
|
||||||
accept4
|
|
||||||
bind // (*)
|
|
||||||
connect // (*)
|
|
||||||
getpeername
|
|
||||||
getsockname // (*)
|
|
||||||
getsockopt
|
|
||||||
listen
|
|
||||||
recv
|
|
||||||
recvfrom // (*)
|
|
||||||
recvmmsg
|
|
||||||
recvmsg
|
|
||||||
send
|
|
||||||
sendmmsg
|
|
||||||
sendmsg
|
|
||||||
sendto // (*)
|
|
||||||
setsockopt
|
|
||||||
shutdown
|
|
||||||
socket // (*)
|
|
||||||
socketcall
|
|
||||||
socketpair
|
|
||||||
sethostname // (*)
|
|
||||||
|
|
||||||
// Signal related
|
|
||||||
pause
|
|
||||||
rt_sigaction // (*)
|
|
||||||
rt_sigpending
|
|
||||||
rt_sigprocmask // (*)
|
|
||||||
rt_sigqueueinfo
|
|
||||||
rt_sigreturn // (*)
|
|
||||||
rt_sigsuspend
|
|
||||||
rt_sigtimedwait
|
|
||||||
rt_tgsigqueueinfo
|
|
||||||
sigaction
|
|
||||||
sigaltstack // (*)
|
|
||||||
signal
|
|
||||||
signalfd
|
|
||||||
signalfd4
|
|
||||||
sigpending
|
|
||||||
sigprocmask
|
|
||||||
sigreturn
|
|
||||||
sigsuspend
|
|
||||||
|
|
||||||
// Other needed POSIX
|
|
||||||
alarm
|
|
||||||
brk // (*)
|
|
||||||
clock_adjtime
|
|
||||||
clock_getres
|
|
||||||
clock_gettime
|
|
||||||
clock_nanosleep
|
|
||||||
//clock_settime
|
|
||||||
gettimeofday
|
|
||||||
nanosleep
|
|
||||||
nice
|
|
||||||
sysinfo
|
|
||||||
syslog
|
|
||||||
time
|
|
||||||
timer_create
|
|
||||||
timer_delete
|
|
||||||
timerfd_create
|
|
||||||
timerfd_gettime
|
|
||||||
timerfd_settime
|
|
||||||
timer_getoverrun
|
|
||||||
timer_gettime
|
|
||||||
timer_settime
|
|
||||||
times
|
|
||||||
uname // (*)
|
|
||||||
|
|
||||||
// Memory control
|
|
||||||
madvise
|
|
||||||
mbind
|
|
||||||
mincore
|
|
||||||
mlock
|
|
||||||
mlockall
|
|
||||||
mmap // (*)
|
|
||||||
mmap2
|
|
||||||
mprotect // (*)
|
|
||||||
mremap
|
|
||||||
msync
|
|
||||||
munlock
|
|
||||||
munlockall
|
|
||||||
munmap // (*)
|
|
||||||
remap_file_pages
|
|
||||||
set_mempolicy
|
|
||||||
vmsplice
|
|
||||||
|
|
||||||
// Process control
|
|
||||||
capget
|
|
||||||
capset // (*)
|
|
||||||
clone // (*)
|
|
||||||
execve // (*)
|
|
||||||
exit // (*)
|
|
||||||
exit_group // (*)
|
|
||||||
fork
|
|
||||||
getcpu
|
|
||||||
getpgid
|
|
||||||
getpgrp // (*)
|
|
||||||
getpid // (*)
|
|
||||||
getppid // (*)
|
|
||||||
getpriority
|
|
||||||
getresgid
|
|
||||||
getresgid32
|
|
||||||
getresuid
|
|
||||||
getresuid32
|
|
||||||
getrlimit // (*)
|
|
||||||
getrusage
|
|
||||||
getsid
|
|
||||||
getuid // (*)
|
|
||||||
getuid32
|
|
||||||
getegid // (*)
|
|
||||||
getegid32
|
|
||||||
geteuid // (*)
|
|
||||||
geteuid32
|
|
||||||
getgid // (*)
|
|
||||||
getgid32
|
|
||||||
getgroups
|
|
||||||
getgroups32
|
|
||||||
getitimer
|
|
||||||
get_mempolicy
|
|
||||||
kill
|
|
||||||
//personality
|
|
||||||
prctl
|
|
||||||
prlimit64
|
|
||||||
sched_getaffinity
|
|
||||||
sched_getparam
|
|
||||||
sched_get_priority_max
|
|
||||||
sched_get_priority_min
|
|
||||||
sched_getscheduler
|
|
||||||
sched_rr_get_interval
|
|
||||||
//sched_setaffinity
|
|
||||||
//sched_setparam
|
|
||||||
//sched_setscheduler
|
|
||||||
sched_yield
|
|
||||||
setfsgid
|
|
||||||
setfsgid32
|
|
||||||
setfsuid
|
|
||||||
setfsuid32
|
|
||||||
setgid
|
|
||||||
setgid32
|
|
||||||
setgroups
|
|
||||||
setgroups32
|
|
||||||
setitimer
|
|
||||||
setpgid // (*)
|
|
||||||
setpriority
|
|
||||||
setregid
|
|
||||||
setregid32
|
|
||||||
setresgid
|
|
||||||
setresgid32
|
|
||||||
setresuid
|
|
||||||
setresuid32
|
|
||||||
setreuid
|
|
||||||
setreuid32
|
|
||||||
setrlimit
|
|
||||||
setsid
|
|
||||||
setuid
|
|
||||||
setuid32
|
|
||||||
ugetrlimit
|
|
||||||
vfork
|
|
||||||
wait4 // (*)
|
|
||||||
waitid
|
|
||||||
waitpid
|
|
||||||
|
|
||||||
// IPC
|
|
||||||
ipc
|
|
||||||
mq_getsetattr
|
|
||||||
mq_notify
|
|
||||||
mq_open
|
|
||||||
mq_timedreceive
|
|
||||||
mq_timedsend
|
|
||||||
mq_unlink
|
|
||||||
msgctl
|
|
||||||
msgget
|
|
||||||
msgrcv
|
|
||||||
msgsnd
|
|
||||||
semctl
|
|
||||||
semget
|
|
||||||
semop
|
|
||||||
semtimedop
|
|
||||||
shmat
|
|
||||||
shmctl
|
|
||||||
shmdt
|
|
||||||
shmget
|
|
||||||
|
|
||||||
// Linux specific, mostly needed for thread-related stuff
|
|
||||||
arch_prctl // (*)
|
|
||||||
get_robust_list
|
|
||||||
get_thread_area
|
|
||||||
gettid
|
|
||||||
futex // (*)
|
|
||||||
restart_syscall // (*)
|
|
||||||
set_robust_list // (*)
|
|
||||||
set_thread_area
|
|
||||||
set_tid_address // (*)
|
|
||||||
tgkill
|
|
||||||
tkill
|
|
||||||
|
|
||||||
// Admin syscalls, these are blocked
|
|
||||||
//acct
|
|
||||||
//adjtimex
|
|
||||||
//bdflush
|
|
||||||
//chroot
|
|
||||||
//create_module
|
|
||||||
//delete_module
|
|
||||||
//get_kernel_syms // Obsolete
|
|
||||||
//idle // Obsolete
|
|
||||||
//init_module
|
|
||||||
//ioperm
|
|
||||||
//iopl
|
|
||||||
//ioprio_get
|
|
||||||
//ioprio_set
|
|
||||||
//kexec_load
|
|
||||||
//lookup_dcookie // oprofile only?
|
|
||||||
//migrate_pages // NUMA
|
|
||||||
//modify_ldt
|
|
||||||
//mount
|
|
||||||
//move_pages // NUMA
|
|
||||||
//name_to_handle_at // NFS server
|
|
||||||
//nfsservctl // NFS server
|
|
||||||
//open_by_handle_at // NFS server
|
|
||||||
//perf_event_open
|
|
||||||
//pivot_root
|
|
||||||
//process_vm_readv // For debugger
|
|
||||||
//process_vm_writev // For debugger
|
|
||||||
//ptrace // For debugger
|
|
||||||
//query_module
|
|
||||||
//quotactl
|
|
||||||
//reboot
|
|
||||||
//setdomainname
|
|
||||||
//setns
|
|
||||||
//settimeofday
|
|
||||||
//sgetmask // Obsolete
|
|
||||||
//ssetmask // Obsolete
|
|
||||||
//stime
|
|
||||||
//swapoff
|
|
||||||
//swapon
|
|
||||||
//_sysctl
|
|
||||||
//sysfs
|
|
||||||
//sys_setaltroot
|
|
||||||
//umount
|
|
||||||
//umount2
|
|
||||||
//unshare
|
|
||||||
//uselib
|
|
||||||
//vhangup
|
|
||||||
//vm86
|
|
||||||
//vm86old
|
|
||||||
|
|
||||||
// Kernel key management
|
|
||||||
//add_key
|
|
||||||
//keyctl
|
|
||||||
//request_key
|
|
||||||
|
|
||||||
// Unimplemented
|
|
||||||
//afs_syscall
|
|
||||||
//break
|
|
||||||
//ftime
|
|
||||||
//getpmsg
|
|
||||||
//gtty
|
|
||||||
//lock
|
|
||||||
//madvise1
|
|
||||||
//mpx
|
|
||||||
//prof
|
|
||||||
//profil
|
|
||||||
//putpmsg
|
|
||||||
//security
|
|
||||||
//stty
|
|
||||||
//tuxcall
|
|
||||||
//ulimit
|
|
||||||
//vserver
|
|
|
@ -25,7 +25,7 @@ The initial Docker upstart script will not work because it runs on `127.0.0.1`,
|
||||||
```
|
```
|
||||||
description "Docker daemon"
|
description "Docker daemon"
|
||||||
|
|
||||||
start on filesystem and started lxc-net
|
start on filesystem
|
||||||
stop on runlevel [!2345]
|
stop on runlevel [!2345]
|
||||||
|
|
||||||
respawn
|
respawn
|
||||||
|
|
|
@ -17,8 +17,6 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config defines the configuration of a docker daemon.
|
// Config defines the configuration of a docker daemon.
|
||||||
// These are the configuration settings that you pass
|
|
||||||
// to the docker daemon when you launch it with say: `docker daemon -e lxc`
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
CommonConfig
|
CommonConfig
|
||||||
|
|
||||||
|
|
|
@ -261,7 +261,6 @@ func (container *Container) jsonPath() (string, error) {
|
||||||
return container.getRootResourcePath("config.json")
|
return container.getRootResourcePath("config.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method must be exported to be used from the lxc template
|
|
||||||
// This directory is only usable when the container is running
|
// This directory is only usable when the container is running
|
||||||
func (container *Container) rootfsPath() string {
|
func (container *Container) rootfsPath() string {
|
||||||
return container.basefs
|
return container.basefs
|
||||||
|
|
|
@ -255,12 +255,6 @@ func (daemon *Daemon) populateCommand(c *Container, env []string) error {
|
||||||
|
|
||||||
autoCreatedDevices := mergeDevices(configs.DefaultAutoCreatedDevices, userSpecifiedDevices)
|
autoCreatedDevices := mergeDevices(configs.DefaultAutoCreatedDevices, userSpecifiedDevices)
|
||||||
|
|
||||||
// TODO: this can be removed after lxc-conf is fully deprecated
|
|
||||||
lxcConfig, err := mergeLxcConfIntoOptions(c.hostConfig)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var rlimits []*ulimit.Rlimit
|
var rlimits []*ulimit.Rlimit
|
||||||
ulimits := c.hostConfig.Ulimits
|
ulimits := c.hostConfig.Ulimits
|
||||||
|
|
||||||
|
@ -345,7 +339,6 @@ func (daemon *Daemon) populateCommand(c *Container, env []string) error {
|
||||||
GIDMapping: gidMap,
|
GIDMapping: gidMap,
|
||||||
GroupAdd: c.hostConfig.GroupAdd,
|
GroupAdd: c.hostConfig.GroupAdd,
|
||||||
Ipc: ipc,
|
Ipc: ipc,
|
||||||
LxcConfig: lxcConfig,
|
|
||||||
Pid: pid,
|
Pid: pid,
|
||||||
ReadonlyRootfs: c.hostConfig.ReadonlyRootfs,
|
ReadonlyRootfs: c.hostConfig.ReadonlyRootfs,
|
||||||
RemappedRoot: remappedRoot,
|
RemappedRoot: remappedRoot,
|
||||||
|
|
|
@ -451,7 +451,6 @@ func (daemon *Daemon) generateNewName(id string) (string, error) {
|
||||||
|
|
||||||
func (daemon *Daemon) generateHostname(id string, config *runconfig.Config) {
|
func (daemon *Daemon) generateHostname(id string, config *runconfig.Config) {
|
||||||
// Generate default hostname
|
// Generate default hostname
|
||||||
// FIXME: the lxc template no longer needs to set a default hostname
|
|
||||||
if config.Hostname == "" {
|
if config.Hostname == "" {
|
||||||
config.Hostname = id[:12]
|
config.Hostname = id[:12]
|
||||||
}
|
}
|
||||||
|
@ -786,13 +785,6 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
|
||||||
d.containerGraphDB = graph
|
d.containerGraphDB = graph
|
||||||
|
|
||||||
var sysInitPath string
|
var sysInitPath string
|
||||||
if config.ExecDriver == "lxc" {
|
|
||||||
initPath, err := configureSysInit(config, rootUID, rootGID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
sysInitPath = initPath
|
|
||||||
}
|
|
||||||
|
|
||||||
sysInfo := sysinfo.New(false)
|
sysInfo := sysinfo.New(false)
|
||||||
// Check if Devices cgroup is mounted, it is hard requirement for container security,
|
// Check if Devices cgroup is mounted, it is hard requirement for container security,
|
||||||
|
|
|
@ -128,10 +128,6 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *runconfig.HostC
|
||||||
return warnings, err
|
return warnings, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if hostConfig.LxcConf.Len() > 0 && !strings.Contains(daemon.ExecutionDriver().Name(), "lxc") {
|
|
||||||
return warnings, fmt.Errorf("Cannot use --lxc-conf with execdriver: %s", daemon.ExecutionDriver().Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
// memory subsystem checks and adjustments
|
// memory subsystem checks and adjustments
|
||||||
if hostConfig.Memory != 0 && hostConfig.Memory < 4194304 {
|
if hostConfig.Memory != 0 && hostConfig.Memory < 4194304 {
|
||||||
return warnings, fmt.Errorf("Minimum memory limit allowed is 4MB")
|
return warnings, fmt.Errorf("Minimum memory limit allowed is 4MB")
|
||||||
|
|
|
@ -148,11 +148,6 @@ func (d *Daemon) getActiveContainer(name string) (*Container, error) {
|
||||||
|
|
||||||
// ContainerExecCreate sets up an exec in a running container.
|
// ContainerExecCreate sets up an exec in a running container.
|
||||||
func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, error) {
|
func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, error) {
|
||||||
// Not all drivers support Exec (LXC for example)
|
|
||||||
if err := checkExecSupport(d.execDriver.Name()); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
container, err := d.getActiveContainer(config.Container)
|
container, err := d.getActiveContainer(config.Container)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
// +build freebsd
|
|
||||||
|
|
||||||
package daemon
|
|
||||||
|
|
||||||
// checkExecSupport returns an error if the exec driver does not support exec,
|
|
||||||
// or nil if it is supported.
|
|
||||||
func checkExecSupport(drivername string) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package daemon
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/docker/daemon/execdriver/lxc"
|
|
||||||
)
|
|
||||||
|
|
||||||
// checkExecSupport returns an error if the exec driver does not support exec,
|
|
||||||
// or nil if it is supported.
|
|
||||||
func checkExecSupport(drivername string) error {
|
|
||||||
if strings.HasPrefix(drivername, lxc.DriverName) {
|
|
||||||
return lxc.ErrExec
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package daemon
|
|
||||||
|
|
||||||
// checkExecSupport returns an error if the exec driver does not support exec,
|
|
||||||
// or nil if it is supported.
|
|
||||||
func checkExecSupport(DriverName string) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -100,7 +100,6 @@ type Command struct {
|
||||||
GIDMapping []idtools.IDMap `json:"gidmapping"`
|
GIDMapping []idtools.IDMap `json:"gidmapping"`
|
||||||
GroupAdd []string `json:"group_add"`
|
GroupAdd []string `json:"group_add"`
|
||||||
Ipc *Ipc `json:"ipc"`
|
Ipc *Ipc `json:"ipc"`
|
||||||
LxcConfig []string `json:"lxc_config"`
|
|
||||||
Pid *Pid `json:"pid"`
|
Pid *Pid `json:"pid"`
|
||||||
ReadonlyRootfs bool `json:"readonly_rootfs"`
|
ReadonlyRootfs bool `json:"readonly_rootfs"`
|
||||||
RemappedRoot *User `json:"remap_root"`
|
RemappedRoot *User `json:"remap_root"`
|
||||||
|
|
|
@ -6,24 +6,15 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/docker/daemon/execdriver"
|
"github.com/docker/docker/daemon/execdriver"
|
||||||
"github.com/docker/docker/daemon/execdriver/lxc"
|
|
||||||
"github.com/docker/docker/daemon/execdriver/native"
|
"github.com/docker/docker/daemon/execdriver/native"
|
||||||
"github.com/docker/docker/pkg/sysinfo"
|
"github.com/docker/docker/pkg/sysinfo"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewDriver returns a new execdriver.Driver from the given name configured with the provided options.
|
// NewDriver returns a new execdriver.Driver from the given name configured with the provided options.
|
||||||
func NewDriver(name string, options []string, root, libPath, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) {
|
func NewDriver(name string, options []string, root, libPath, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) {
|
||||||
switch name {
|
if name != "native" {
|
||||||
case "lxc":
|
return nil, fmt.Errorf("unknown exec driver %s", name)
|
||||||
// we want to give the lxc driver the full docker root because it needs
|
|
||||||
// to access and write config and template files in /var/lib/docker/containers/*
|
|
||||||
// to be backwards compatible
|
|
||||||
logrus.Warn("LXC built-in support is deprecated.")
|
|
||||||
return lxc.NewDriver(root, libPath, initPath, sysInfo.AppArmor)
|
|
||||||
case "native":
|
|
||||||
return native.NewDriver(path.Join(root, "execdriver", "native"), initPath, options)
|
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("unknown exec driver %s", name)
|
return native.NewDriver(path.Join(root, "execdriver", "native"), initPath, options)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,906 +0,0 @@
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package lxc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/docker/daemon/execdriver"
|
|
||||||
"github.com/docker/docker/pkg/stringutils"
|
|
||||||
sysinfo "github.com/docker/docker/pkg/system"
|
|
||||||
"github.com/docker/docker/pkg/term"
|
|
||||||
"github.com/docker/docker/pkg/version"
|
|
||||||
"github.com/kr/pty"
|
|
||||||
"github.com/opencontainers/runc/libcontainer"
|
|
||||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
|
||||||
"github.com/opencontainers/runc/libcontainer/system"
|
|
||||||
"github.com/opencontainers/runc/libcontainer/user"
|
|
||||||
"github.com/vishvananda/netns"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DriverName for lxc driver
|
|
||||||
const DriverName = "lxc"
|
|
||||||
|
|
||||||
// ErrExec defines unsupported error message
|
|
||||||
var ErrExec = errors.New("Unsupported: Exec is not supported by the lxc driver")
|
|
||||||
|
|
||||||
// Driver contains all information for lxc driver,
|
|
||||||
// it implements execdriver.Driver
|
|
||||||
type Driver struct {
|
|
||||||
root string // root path for the driver to use
|
|
||||||
libPath string
|
|
||||||
initPath string
|
|
||||||
apparmor bool
|
|
||||||
sharedRoot bool
|
|
||||||
activeContainers map[string]*activeContainer
|
|
||||||
machineMemory int64
|
|
||||||
sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
type activeContainer struct {
|
|
||||||
container *configs.Config
|
|
||||||
cmd *exec.Cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDriver returns a new lxc driver, called from NewDriver of execdriver
|
|
||||||
func NewDriver(root, libPath, initPath string, apparmor bool) (*Driver, error) {
|
|
||||||
if err := os.MkdirAll(root, 0700); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// setup unconfined symlink
|
|
||||||
if err := linkLxcStart(root); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
meminfo, err := sysinfo.ReadMemInfo()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &Driver{
|
|
||||||
apparmor: apparmor,
|
|
||||||
root: root,
|
|
||||||
libPath: libPath,
|
|
||||||
initPath: initPath,
|
|
||||||
sharedRoot: rootIsShared(),
|
|
||||||
activeContainers: make(map[string]*activeContainer),
|
|
||||||
machineMemory: meminfo.MemTotal,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name implements the exec driver Driver interface.
|
|
||||||
func (d *Driver) Name() string {
|
|
||||||
version := d.version()
|
|
||||||
return fmt.Sprintf("%s-%s", DriverName, version)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupNetNs(nsPath string) (*os.Process, error) {
|
|
||||||
runtime.LockOSThread()
|
|
||||||
defer runtime.UnlockOSThread()
|
|
||||||
|
|
||||||
origns, err := netns.Get()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer origns.Close()
|
|
||||||
|
|
||||||
f, err := os.OpenFile(nsPath, os.O_RDONLY, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get network namespace %q: %v", nsPath, err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
nsFD := f.Fd()
|
|
||||||
if err := netns.Set(netns.NsHandle(nsFD)); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to set network namespace %q: %v", nsPath, err)
|
|
||||||
}
|
|
||||||
defer netns.Set(origns)
|
|
||||||
|
|
||||||
cmd := exec.Command("/bin/sh", "-c", "while true; do sleep 1; done")
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to start netns process: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmd.Process, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func killNetNsProc(proc *os.Process) {
|
|
||||||
proc.Kill()
|
|
||||||
proc.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run implements the exec driver Driver interface,
|
|
||||||
// it calls 'exec.Cmd' to launch lxc commands to run a container.
|
|
||||||
func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) {
|
|
||||||
var (
|
|
||||||
term execdriver.Terminal
|
|
||||||
err error
|
|
||||||
dataPath = d.containerDir(c.ID)
|
|
||||||
)
|
|
||||||
|
|
||||||
if c.Network == nil || (c.Network.NamespacePath == "" && c.Network.ContainerID == "") {
|
|
||||||
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("empty namespace path for non-container network")
|
|
||||||
}
|
|
||||||
|
|
||||||
container, err := d.createContainer(c)
|
|
||||||
if err != nil {
|
|
||||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.ProcessConfig.Tty {
|
|
||||||
term, err = NewTtyConsole(&c.ProcessConfig, pipes)
|
|
||||||
} else {
|
|
||||||
term, err = execdriver.NewStdConsole(&c.ProcessConfig, pipes)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
|
||||||
}
|
|
||||||
c.ProcessConfig.Terminal = term
|
|
||||||
|
|
||||||
d.Lock()
|
|
||||||
d.activeContainers[c.ID] = &activeContainer{
|
|
||||||
container: container,
|
|
||||||
cmd: &c.ProcessConfig.Cmd,
|
|
||||||
}
|
|
||||||
d.Unlock()
|
|
||||||
|
|
||||||
c.Mounts = append(c.Mounts, execdriver.Mount{
|
|
||||||
Source: d.initPath,
|
|
||||||
Destination: c.InitPath,
|
|
||||||
Writable: false,
|
|
||||||
Private: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err := d.generateEnvConfig(c); err != nil {
|
|
||||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
|
||||||
}
|
|
||||||
configPath, err := d.generateLXCConfig(c)
|
|
||||||
if err != nil {
|
|
||||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
|
||||||
}
|
|
||||||
params := []string{
|
|
||||||
"lxc-start",
|
|
||||||
"-n", c.ID,
|
|
||||||
"-f", configPath,
|
|
||||||
"-q",
|
|
||||||
}
|
|
||||||
|
|
||||||
// From lxc>=1.1 the default behavior is to daemonize containers after start
|
|
||||||
lxcVersion := version.Version(d.version())
|
|
||||||
if lxcVersion.GreaterThanOrEqualTo(version.Version("1.1")) {
|
|
||||||
params = append(params, "-F")
|
|
||||||
}
|
|
||||||
|
|
||||||
proc := &os.Process{}
|
|
||||||
if c.Network.ContainerID != "" {
|
|
||||||
params = append(params,
|
|
||||||
"--share-net", c.Network.ContainerID,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
proc, err = setupNetNs(c.Network.NamespacePath)
|
|
||||||
if err != nil {
|
|
||||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pidStr := fmt.Sprintf("%d", proc.Pid)
|
|
||||||
params = append(params,
|
|
||||||
"--share-net", pidStr)
|
|
||||||
}
|
|
||||||
if c.Ipc != nil {
|
|
||||||
if c.Ipc.ContainerID != "" {
|
|
||||||
params = append(params,
|
|
||||||
"--share-ipc", c.Ipc.ContainerID,
|
|
||||||
)
|
|
||||||
} else if c.Ipc.HostIpc {
|
|
||||||
params = append(params,
|
|
||||||
"--share-ipc", "1",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
params = append(params,
|
|
||||||
"--",
|
|
||||||
c.InitPath,
|
|
||||||
)
|
|
||||||
|
|
||||||
if c.ProcessConfig.User != "" {
|
|
||||||
params = append(params, "-u", c.ProcessConfig.User)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.ProcessConfig.Privileged {
|
|
||||||
if d.apparmor {
|
|
||||||
params[0] = path.Join(d.root, "lxc-start-unconfined")
|
|
||||||
|
|
||||||
}
|
|
||||||
params = append(params, "-privileged")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.WorkingDir != "" {
|
|
||||||
params = append(params, "-w", c.WorkingDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
params = append(params, "--", c.ProcessConfig.Entrypoint)
|
|
||||||
params = append(params, c.ProcessConfig.Arguments...)
|
|
||||||
|
|
||||||
if d.sharedRoot {
|
|
||||||
// lxc-start really needs / to be non-shared, or all kinds of stuff break
|
|
||||||
// when lxc-start unmount things and those unmounts propagate to the main
|
|
||||||
// mount namespace.
|
|
||||||
// What we really want is to clone into a new namespace and then
|
|
||||||
// mount / MS_REC|MS_SLAVE, but since we can't really clone or fork
|
|
||||||
// without exec in go we have to do this horrible shell hack...
|
|
||||||
shellString :=
|
|
||||||
"mount --make-rslave /; exec " +
|
|
||||||
stringutils.ShellQuoteArguments(params)
|
|
||||||
|
|
||||||
params = []string{
|
|
||||||
"unshare", "-m", "--", "/bin/sh", "-c", shellString,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logrus.Debugf("lxc params %s", params)
|
|
||||||
var (
|
|
||||||
name = params[0]
|
|
||||||
arg = params[1:]
|
|
||||||
)
|
|
||||||
aname, err := exec.LookPath(name)
|
|
||||||
if err != nil {
|
|
||||||
aname = name
|
|
||||||
}
|
|
||||||
c.ProcessConfig.Path = aname
|
|
||||||
c.ProcessConfig.Args = append([]string{name}, arg...)
|
|
||||||
|
|
||||||
if err := createDeviceNodes(c.Rootfs, c.AutoCreatedDevices); err != nil {
|
|
||||||
killNetNsProc(proc)
|
|
||||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.ProcessConfig.Start(); err != nil {
|
|
||||||
killNetNsProc(proc)
|
|
||||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
waitErr error
|
|
||||||
waitLock = make(chan struct{})
|
|
||||||
)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
if err := c.ProcessConfig.Wait(); err != nil {
|
|
||||||
if _, ok := err.(*exec.ExitError); !ok { // Do not propagate the error if it's simply a status code != 0
|
|
||||||
waitErr = err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(waitLock)
|
|
||||||
}()
|
|
||||||
|
|
||||||
terminate := func(terr error) (execdriver.ExitStatus, error) {
|
|
||||||
if c.ProcessConfig.Process != nil {
|
|
||||||
c.ProcessConfig.Process.Kill()
|
|
||||||
c.ProcessConfig.Wait()
|
|
||||||
}
|
|
||||||
return execdriver.ExitStatus{ExitCode: -1}, terr
|
|
||||||
}
|
|
||||||
// Poll lxc for RUNNING status
|
|
||||||
pid, err := d.waitForStart(c, waitLock)
|
|
||||||
if err != nil {
|
|
||||||
killNetNsProc(proc)
|
|
||||||
return terminate(err)
|
|
||||||
}
|
|
||||||
killNetNsProc(proc)
|
|
||||||
|
|
||||||
cgroupPaths, err := cgroupPaths(c.ID)
|
|
||||||
if err != nil {
|
|
||||||
return terminate(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
state := &libcontainer.State{
|
|
||||||
InitProcessPid: pid,
|
|
||||||
CgroupPaths: cgroupPaths,
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := os.Create(filepath.Join(dataPath, "state.json"))
|
|
||||||
if err != nil {
|
|
||||||
return terminate(err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
if err := json.NewEncoder(f).Encode(state); err != nil {
|
|
||||||
return terminate(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ContainerPid = pid
|
|
||||||
|
|
||||||
if hooks.Start != nil {
|
|
||||||
logrus.Debugf("Invoking startCallback")
|
|
||||||
chOOM := make(chan struct{})
|
|
||||||
close(chOOM)
|
|
||||||
hooks.Start(&c.ProcessConfig, pid, chOOM)
|
|
||||||
}
|
|
||||||
|
|
||||||
oomKillNotification := notifyChannelOOM(cgroupPaths)
|
|
||||||
|
|
||||||
<-waitLock
|
|
||||||
exitCode := getExitCode(c)
|
|
||||||
|
|
||||||
_, oomKill := <-oomKillNotification
|
|
||||||
logrus.Debugf("oomKill error: %v, waitErr: %v", oomKill, waitErr)
|
|
||||||
|
|
||||||
// check oom error
|
|
||||||
if oomKill {
|
|
||||||
exitCode = 137
|
|
||||||
}
|
|
||||||
|
|
||||||
return execdriver.ExitStatus{ExitCode: exitCode, OOMKilled: oomKill}, waitErr
|
|
||||||
}
|
|
||||||
|
|
||||||
func notifyChannelOOM(paths map[string]string) <-chan struct{} {
|
|
||||||
oom, err := notifyOnOOM(paths)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Warnf("Your kernel does not support OOM notifications: %s", err)
|
|
||||||
c := make(chan struct{})
|
|
||||||
close(c)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
return oom
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy from libcontainer
|
|
||||||
func notifyOnOOM(paths map[string]string) (<-chan struct{}, error) {
|
|
||||||
dir := paths["memory"]
|
|
||||||
if dir == "" {
|
|
||||||
return nil, fmt.Errorf("There is no path for %q in state", "memory")
|
|
||||||
}
|
|
||||||
oomControl, err := os.Open(filepath.Join(dir, "memory.oom_control"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
fd, _, syserr := syscall.RawSyscall(syscall.SYS_EVENTFD2, 0, syscall.FD_CLOEXEC, 0)
|
|
||||||
if syserr != 0 {
|
|
||||||
oomControl.Close()
|
|
||||||
return nil, syserr
|
|
||||||
}
|
|
||||||
|
|
||||||
eventfd := os.NewFile(fd, "eventfd")
|
|
||||||
|
|
||||||
eventControlPath := filepath.Join(dir, "cgroup.event_control")
|
|
||||||
data := fmt.Sprintf("%d %d", eventfd.Fd(), oomControl.Fd())
|
|
||||||
if err := ioutil.WriteFile(eventControlPath, []byte(data), 0700); err != nil {
|
|
||||||
eventfd.Close()
|
|
||||||
oomControl.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ch := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
defer func() {
|
|
||||||
close(ch)
|
|
||||||
eventfd.Close()
|
|
||||||
oomControl.Close()
|
|
||||||
}()
|
|
||||||
buf := make([]byte, 8)
|
|
||||||
for {
|
|
||||||
if _, err := eventfd.Read(buf); err != nil {
|
|
||||||
logrus.Warn(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// When a cgroup is destroyed, an event is sent to eventfd.
|
|
||||||
// So if the control path is gone, return instead of notifying.
|
|
||||||
if _, err := os.Lstat(eventControlPath); os.IsNotExist(err) {
|
|
||||||
logrus.Warn(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ch <- struct{}{}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return ch, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// createContainer populates and configures the container type with the
|
|
||||||
// data provided by the execdriver.Command
|
|
||||||
func (d *Driver) createContainer(c *execdriver.Command) (*configs.Config, error) {
|
|
||||||
container := execdriver.InitContainer(c)
|
|
||||||
if err := execdriver.SetupCgroups(container, c); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return container, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return an map of susbystem -> absolute container cgroup path
|
|
||||||
func cgroupPaths(containerID string) (map[string]string, error) {
|
|
||||||
subsystems, err := cgroups.GetAllSubsystems()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logrus.Debugf("subsystems: %s", subsystems)
|
|
||||||
paths := make(map[string]string)
|
|
||||||
for _, subsystem := range subsystems {
|
|
||||||
cgroupRoot, cgroupDir, err := findCgroupRootAndDir(subsystem)
|
|
||||||
logrus.Debugf("cgroup path %s %s", cgroupRoot, cgroupDir)
|
|
||||||
if err != nil {
|
|
||||||
//unsupported subystem
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// if we are running dind
|
|
||||||
dockerPathIdx := strings.LastIndex(cgroupDir, "docker")
|
|
||||||
if dockerPathIdx != -1 {
|
|
||||||
cgroupDir = cgroupDir[:dockerPathIdx-1]
|
|
||||||
}
|
|
||||||
path := filepath.Join(cgroupRoot, cgroupDir, "lxc", containerID)
|
|
||||||
paths[subsystem] = path
|
|
||||||
}
|
|
||||||
|
|
||||||
return paths, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is copy from old libcontainer nodes.go
|
|
||||||
func createDeviceNodes(rootfs string, nodesToCreate []*configs.Device) error {
|
|
||||||
oldMask := syscall.Umask(0000)
|
|
||||||
defer syscall.Umask(oldMask)
|
|
||||||
|
|
||||||
for _, node := range nodesToCreate {
|
|
||||||
if err := createDeviceNode(rootfs, node); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates the device node in the rootfs of the container.
|
|
||||||
func createDeviceNode(rootfs string, node *configs.Device) error {
|
|
||||||
var (
|
|
||||||
dest = filepath.Join(rootfs, node.Path)
|
|
||||||
parent = filepath.Dir(dest)
|
|
||||||
)
|
|
||||||
|
|
||||||
if err := os.MkdirAll(parent, 0755); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fileMode := node.FileMode
|
|
||||||
switch node.Type {
|
|
||||||
case 'c':
|
|
||||||
fileMode |= syscall.S_IFCHR
|
|
||||||
case 'b':
|
|
||||||
fileMode |= syscall.S_IFBLK
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("%c is not a valid device type for device %s", node.Type, node.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := syscall.Mknod(dest, uint32(fileMode), node.Mkdev()); err != nil && !os.IsExist(err) {
|
|
||||||
return fmt.Errorf("mknod %s %s", node.Path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := syscall.Chown(dest, int(node.Uid), int(node.Gid)); err != nil {
|
|
||||||
return fmt.Errorf("chown %s to %d:%d", node.Path, node.Uid, node.Gid)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// setupUser changes the groups, gid, and uid for the user inside the container
|
|
||||||
// copy from libcontainer, cause not it's private
|
|
||||||
func setupUser(userSpec string) error {
|
|
||||||
// Set up defaults.
|
|
||||||
defaultExecUser := user.ExecUser{
|
|
||||||
Uid: syscall.Getuid(),
|
|
||||||
Gid: syscall.Getgid(),
|
|
||||||
Home: "/",
|
|
||||||
}
|
|
||||||
passwdPath, err := user.GetPasswdPath()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
groupPath, err := user.GetGroupPath()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
execUser, err := user.GetExecUserPath(userSpec, &defaultExecUser, passwdPath, groupPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := syscall.Setgroups(execUser.Sgids); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := system.Setgid(execUser.Gid); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := system.Setuid(execUser.Uid); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// if we didn't get HOME already, set it based on the user's HOME
|
|
||||||
if envHome := os.Getenv("HOME"); envHome == "" {
|
|
||||||
if err := os.Setenv("HOME", execUser.Home); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getExitCode returns the exit code of the process.
|
|
||||||
// If the process has not exited -1 will be returned.
|
|
||||||
func getExitCode(c *execdriver.Command) int {
|
|
||||||
if c.ProcessConfig.ProcessState == nil {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return c.ProcessConfig.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kill implements the exec driver Driver interface.
|
|
||||||
func (d *Driver) Kill(c *execdriver.Command, sig int) error {
|
|
||||||
if sig == 9 || c.ProcessConfig.Process == nil {
|
|
||||||
return killLxc(c.ID, sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.ProcessConfig.Process.Signal(syscall.Signal(sig))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pause implements the exec driver Driver interface,
|
|
||||||
// it executes lxc-freeze to pause a container.
|
|
||||||
func (d *Driver) Pause(c *execdriver.Command) error {
|
|
||||||
_, err := exec.LookPath("lxc-freeze")
|
|
||||||
if err == nil {
|
|
||||||
output, errExec := exec.Command("lxc-freeze", "-n", c.ID).CombinedOutput()
|
|
||||||
if errExec != nil {
|
|
||||||
return fmt.Errorf("Err: %s Output: %s", errExec, output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unpause implements the exec driver Driver interface,
|
|
||||||
// it executes lxc-unfreeze to unpause a container.
|
|
||||||
func (d *Driver) Unpause(c *execdriver.Command) error {
|
|
||||||
_, err := exec.LookPath("lxc-unfreeze")
|
|
||||||
if err == nil {
|
|
||||||
output, errExec := exec.Command("lxc-unfreeze", "-n", c.ID).CombinedOutput()
|
|
||||||
if errExec != nil {
|
|
||||||
return fmt.Errorf("Err: %s Output: %s", errExec, output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Terminate implements the exec driver Driver interface.
|
|
||||||
func (d *Driver) Terminate(c *execdriver.Command) error {
|
|
||||||
return killLxc(c.ID, 9)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Driver) version() string {
|
|
||||||
var (
|
|
||||||
version string
|
|
||||||
output []byte
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
if _, errPath := exec.LookPath("lxc-version"); errPath == nil {
|
|
||||||
output, err = exec.Command("lxc-version").CombinedOutput()
|
|
||||||
} else {
|
|
||||||
output, err = exec.Command("lxc-start", "--version").CombinedOutput()
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
version = strings.TrimSpace(string(output))
|
|
||||||
if parts := strings.SplitN(version, ":", 2); len(parts) == 2 {
|
|
||||||
version = strings.TrimSpace(parts[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return version
|
|
||||||
}
|
|
||||||
|
|
||||||
func killLxc(id string, sig int) error {
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
output []byte
|
|
||||||
)
|
|
||||||
_, err = exec.LookPath("lxc-kill")
|
|
||||||
if err == nil {
|
|
||||||
output, err = exec.Command("lxc-kill", "-n", id, strconv.Itoa(sig)).CombinedOutput()
|
|
||||||
} else {
|
|
||||||
// lxc-stop does not take arbitrary signals like lxc-kill does
|
|
||||||
output, err = exec.Command("lxc-stop", "-k", "-n", id).CombinedOutput()
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Err: %s Output: %s", err, output)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait for the process to start and return the pid for the process
|
|
||||||
func (d *Driver) waitForStart(c *execdriver.Command, waitLock chan struct{}) (int, error) {
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
output []byte
|
|
||||||
)
|
|
||||||
// We wait for the container to be fully running.
|
|
||||||
// Timeout after 5 seconds. In case of broken pipe, just retry.
|
|
||||||
// Note: The container can run and finish correctly before
|
|
||||||
// the end of this loop
|
|
||||||
for now := time.Now(); time.Since(now) < 5*time.Second; {
|
|
||||||
select {
|
|
||||||
case <-waitLock:
|
|
||||||
// If the process dies while waiting for it, just return
|
|
||||||
return -1, nil
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
output, err = d.getInfo(c.ID)
|
|
||||||
if err == nil {
|
|
||||||
info, err := parseLxcInfo(string(output))
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
if info.Running {
|
|
||||||
return info.Pid, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
time.Sleep(50 * time.Millisecond)
|
|
||||||
}
|
|
||||||
return -1, execdriver.ErrNotRunning
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Driver) getInfo(id string) ([]byte, error) {
|
|
||||||
return exec.Command("lxc-info", "-n", id).CombinedOutput()
|
|
||||||
}
|
|
||||||
|
|
||||||
type info struct {
|
|
||||||
ID string
|
|
||||||
driver *Driver
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *info) IsRunning() bool {
|
|
||||||
var running bool
|
|
||||||
|
|
||||||
output, err := i.driver.getInfo(i.ID)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("Error getting info for lxc container %s: %s (%s)", i.ID, err, output)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if strings.Contains(string(output), "RUNNING") {
|
|
||||||
running = true
|
|
||||||
}
|
|
||||||
return running
|
|
||||||
}
|
|
||||||
|
|
||||||
// Info implements the exec driver Driver interface.
|
|
||||||
func (d *Driver) Info(id string) execdriver.Info {
|
|
||||||
return &info{
|
|
||||||
ID: id,
|
|
||||||
driver: d,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func findCgroupRootAndDir(subsystem string) (string, string, error) {
|
|
||||||
cgroupRoot, err := cgroups.FindCgroupMountpoint(subsystem)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
cgroupDir, err := cgroups.GetThisCgroupDir(subsystem)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
return cgroupRoot, cgroupDir, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPidsForContainer implements the exec driver Driver interface.
|
|
||||||
func (d *Driver) GetPidsForContainer(id string) ([]int, error) {
|
|
||||||
pids := []int{}
|
|
||||||
|
|
||||||
// cpu is chosen because it is the only non optional subsystem in cgroups
|
|
||||||
subsystem := "cpu"
|
|
||||||
cgroupRoot, cgroupDir, err := findCgroupRootAndDir(subsystem)
|
|
||||||
if err != nil {
|
|
||||||
return pids, err
|
|
||||||
}
|
|
||||||
|
|
||||||
filename := filepath.Join(cgroupRoot, cgroupDir, id, "tasks")
|
|
||||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
|
||||||
// With more recent lxc versions use, cgroup will be in lxc/
|
|
||||||
filename = filepath.Join(cgroupRoot, cgroupDir, "lxc", id, "tasks")
|
|
||||||
}
|
|
||||||
|
|
||||||
output, err := ioutil.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
return pids, err
|
|
||||||
}
|
|
||||||
for _, p := range strings.Split(string(output), "\n") {
|
|
||||||
if len(p) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
pid, err := strconv.Atoi(p)
|
|
||||||
if err != nil {
|
|
||||||
return pids, fmt.Errorf("Invalid pid '%s': %s", p, err)
|
|
||||||
}
|
|
||||||
pids = append(pids, pid)
|
|
||||||
}
|
|
||||||
return pids, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func linkLxcStart(root string) error {
|
|
||||||
sourcePath, err := exec.LookPath("lxc-start")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
targetPath := path.Join(root, "lxc-start-unconfined")
|
|
||||||
|
|
||||||
if _, err := os.Lstat(targetPath); err != nil && !os.IsNotExist(err) {
|
|
||||||
return err
|
|
||||||
} else if err == nil {
|
|
||||||
if err := os.Remove(targetPath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return os.Symlink(sourcePath, targetPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: This can be moved to the mountinfo reader in the mount pkg
|
|
||||||
func rootIsShared() bool {
|
|
||||||
if data, err := ioutil.ReadFile("/proc/self/mountinfo"); err == nil {
|
|
||||||
for _, line := range strings.Split(string(data), "\n") {
|
|
||||||
cols := strings.Split(line, " ")
|
|
||||||
if len(cols) >= 6 && cols[4] == "/" {
|
|
||||||
return strings.HasPrefix(cols[6], "shared")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No idea, probably safe to assume so
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Driver) containerDir(containerID string) string {
|
|
||||||
return path.Join(d.libPath, "containers", containerID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Driver) generateLXCConfig(c *execdriver.Command) (string, error) {
|
|
||||||
root := path.Join(d.containerDir(c.ID), "config.lxc")
|
|
||||||
|
|
||||||
fo, err := os.Create(root)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer fo.Close()
|
|
||||||
|
|
||||||
if err := lxcTemplateCompiled.Execute(fo, struct {
|
|
||||||
*execdriver.Command
|
|
||||||
AppArmor bool
|
|
||||||
}{
|
|
||||||
Command: c,
|
|
||||||
AppArmor: d.apparmor,
|
|
||||||
}); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return root, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Driver) generateEnvConfig(c *execdriver.Command) error {
|
|
||||||
data, err := json.Marshal(c.ProcessConfig.Env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
p := path.Join(d.libPath, "containers", c.ID, "config.env")
|
|
||||||
c.Mounts = append(c.Mounts, execdriver.Mount{
|
|
||||||
Source: p,
|
|
||||||
Destination: "/.dockerenv",
|
|
||||||
Writable: false,
|
|
||||||
Private: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
return ioutil.WriteFile(p, data, 0600)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean implements the exec driver Driver interface,
|
|
||||||
// it's not implemented by lxc.
|
|
||||||
func (d *Driver) Clean(id string) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TtyConsole implements the exec driver Terminal interface,
|
|
||||||
// it stores the master and slave ends of the container's pty.
|
|
||||||
type TtyConsole struct {
|
|
||||||
MasterPty *os.File
|
|
||||||
SlavePty *os.File
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTtyConsole returns a new TtyConsole struct.
|
|
||||||
// Wired up to the provided process config and stdin/stdout/stderr pipes.
|
|
||||||
func NewTtyConsole(processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes) (*TtyConsole, error) {
|
|
||||||
// lxc is special in that we cannot create the master outside of the container without
|
|
||||||
// opening the slave because we have nothing to provide to the cmd. We have to open both then do
|
|
||||||
// the crazy setup on command right now instead of passing the console path to lxc and telling it
|
|
||||||
// to open up that console. we save a couple of openfiles in the native driver because we can do
|
|
||||||
// this.
|
|
||||||
ptyMaster, ptySlave, err := pty.Open()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tty := &TtyConsole{
|
|
||||||
MasterPty: ptyMaster,
|
|
||||||
SlavePty: ptySlave,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := tty.AttachPipes(&processConfig.Cmd, pipes); err != nil {
|
|
||||||
tty.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
processConfig.Console = tty.SlavePty.Name()
|
|
||||||
|
|
||||||
return tty, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resize implements Resize method of Terminal interface
|
|
||||||
func (t *TtyConsole) Resize(h, w int) error {
|
|
||||||
return term.SetWinsize(t.MasterPty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
|
|
||||||
}
|
|
||||||
|
|
||||||
// AttachPipes attaches given pipes to exec.Cmd
|
|
||||||
func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *execdriver.Pipes) error {
|
|
||||||
command.Stdout = t.SlavePty
|
|
||||||
command.Stderr = t.SlavePty
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
if wb, ok := pipes.Stdout.(interface {
|
|
||||||
CloseWriters() error
|
|
||||||
}); ok {
|
|
||||||
defer wb.CloseWriters()
|
|
||||||
}
|
|
||||||
|
|
||||||
io.Copy(pipes.Stdout, t.MasterPty)
|
|
||||||
}()
|
|
||||||
|
|
||||||
if pipes.Stdin != nil {
|
|
||||||
command.Stdin = t.SlavePty
|
|
||||||
command.SysProcAttr.Setctty = true
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
io.Copy(t.MasterPty, pipes.Stdin)
|
|
||||||
|
|
||||||
pipes.Stdin.Close()
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close implements Close method of Terminal interface
|
|
||||||
func (t *TtyConsole) Close() error {
|
|
||||||
t.SlavePty.Close()
|
|
||||||
return t.MasterPty.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exec implements the exec driver Driver interface,
|
|
||||||
// it is not implemented by lxc.
|
|
||||||
func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) {
|
|
||||||
return -1, ErrExec
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stats implements the exec driver Driver interface.
|
|
||||||
// Lxc doesn't implement it's own Stats, it does some trick by implementing
|
|
||||||
// execdriver.Stats to get stats info by libcontainer APIs.
|
|
||||||
func (d *Driver) Stats(id string) (*execdriver.ResourceStats, error) {
|
|
||||||
if _, ok := d.activeContainers[id]; !ok {
|
|
||||||
return nil, fmt.Errorf("%s is not a key in active containers", id)
|
|
||||||
}
|
|
||||||
return execdriver.Stats(d.containerDir(id), d.activeContainers[id].container.Cgroups.Memory, d.machineMemory)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SupportsHooks implements the execdriver Driver interface.
|
|
||||||
// The LXC execdriver does not support the hook mechanism, which is currently unique to runC/libcontainer.
|
|
||||||
func (d *Driver) SupportsHooks() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package lxc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"errors"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Define error messages
|
|
||||||
var (
|
|
||||||
ErrCannotParse = errors.New("cannot parse raw input")
|
|
||||||
)
|
|
||||||
|
|
||||||
type lxcInfo struct {
|
|
||||||
Running bool
|
|
||||||
Pid int
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseLxcInfo(raw string) (*lxcInfo, error) {
|
|
||||||
if raw == "" {
|
|
||||||
return nil, ErrCannotParse
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
s = bufio.NewScanner(strings.NewReader(raw))
|
|
||||||
info = &lxcInfo{}
|
|
||||||
)
|
|
||||||
for s.Scan() {
|
|
||||||
text := s.Text()
|
|
||||||
|
|
||||||
if s.Err() != nil {
|
|
||||||
return nil, s.Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := strings.Split(text, ":")
|
|
||||||
if len(parts) < 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch strings.ToLower(strings.TrimSpace(parts[0])) {
|
|
||||||
case "state":
|
|
||||||
info.Running = strings.TrimSpace(parts[1]) == "RUNNING"
|
|
||||||
case "pid":
|
|
||||||
info.Pid, err = strconv.Atoi(strings.TrimSpace(parts[1]))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return info, nil
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package lxc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestParseRunningInfo(t *testing.T) {
|
|
||||||
raw := `
|
|
||||||
state: RUNNING
|
|
||||||
pid: 50`
|
|
||||||
|
|
||||||
info, err := parseLxcInfo(raw)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if !info.Running {
|
|
||||||
t.Fatal("info should return a running state")
|
|
||||||
}
|
|
||||||
if info.Pid != 50 {
|
|
||||||
t.Fatalf("info should have pid 50 got %d", info.Pid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEmptyInfo(t *testing.T) {
|
|
||||||
_, err := parseLxcInfo("")
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("error should not be nil")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBadInfo(t *testing.T) {
|
|
||||||
_, err := parseLxcInfo("state")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,145 +0,0 @@
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package lxc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/docker/pkg/reexec"
|
|
||||||
)
|
|
||||||
|
|
||||||
// InitArgs contains args provided to the init function for a driver
|
|
||||||
type InitArgs struct {
|
|
||||||
User string
|
|
||||||
Gateway string
|
|
||||||
IP string
|
|
||||||
WorkDir string
|
|
||||||
Privileged bool
|
|
||||||
Env []string
|
|
||||||
Args []string
|
|
||||||
Mtu int
|
|
||||||
Console string
|
|
||||||
Pipe int
|
|
||||||
Root string
|
|
||||||
CapAdd string
|
|
||||||
CapDrop string
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// like always lxc requires a hack to get this to work
|
|
||||||
reexec.Register("/.dockerinit", dockerInititalizer)
|
|
||||||
}
|
|
||||||
|
|
||||||
func dockerInititalizer() {
|
|
||||||
initializer()
|
|
||||||
}
|
|
||||||
|
|
||||||
// initializer is the lxc driver's init function that is run inside the namespace to setup
|
|
||||||
// additional configurations
|
|
||||||
func initializer() {
|
|
||||||
runtime.LockOSThread()
|
|
||||||
|
|
||||||
args := getArgs()
|
|
||||||
|
|
||||||
if err := setupNamespace(args); err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupNamespace(args *InitArgs) error {
|
|
||||||
if err := setupEnv(args); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := finalizeNamespace(args); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
path, err := exec.LookPath(args.Args[0])
|
|
||||||
if err != nil {
|
|
||||||
logrus.Infof("Unable to locate %v", args.Args[0])
|
|
||||||
os.Exit(127)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := syscall.Exec(path, args.Args, os.Environ()); err != nil {
|
|
||||||
return fmt.Errorf("dockerinit unable to execute %s - %s", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getArgs() *InitArgs {
|
|
||||||
var (
|
|
||||||
// Get cmdline arguments
|
|
||||||
user = flag.String("u", "", "username or uid")
|
|
||||||
gateway = flag.String("g", "", "gateway address")
|
|
||||||
ip = flag.String("i", "", "ip address")
|
|
||||||
workDir = flag.String("w", "", "workdir")
|
|
||||||
privileged = flag.Bool("privileged", false, "privileged mode")
|
|
||||||
mtu = flag.Int("mtu", 1500, "interface mtu")
|
|
||||||
capAdd = flag.String("cap-add", "", "capabilities to add")
|
|
||||||
capDrop = flag.String("cap-drop", "", "capabilities to drop")
|
|
||||||
)
|
|
||||||
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
return &InitArgs{
|
|
||||||
User: *user,
|
|
||||||
Gateway: *gateway,
|
|
||||||
IP: *ip,
|
|
||||||
WorkDir: *workDir,
|
|
||||||
Privileged: *privileged,
|
|
||||||
Args: flag.Args(),
|
|
||||||
Mtu: *mtu,
|
|
||||||
CapAdd: *capAdd,
|
|
||||||
CapDrop: *capDrop,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear environment pollution introduced by lxc-start
|
|
||||||
func setupEnv(args *InitArgs) error {
|
|
||||||
// Get env
|
|
||||||
var env []string
|
|
||||||
dockerenv, err := os.Open(".dockerenv")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Unable to load environment variables: %v", err)
|
|
||||||
}
|
|
||||||
defer dockerenv.Close()
|
|
||||||
if err := json.NewDecoder(dockerenv).Decode(&env); err != nil {
|
|
||||||
return fmt.Errorf("Unable to decode environment variables: %v", err)
|
|
||||||
}
|
|
||||||
// Propagate the plugin-specific container env variable
|
|
||||||
env = append(env, "container="+os.Getenv("container"))
|
|
||||||
|
|
||||||
args.Env = env
|
|
||||||
|
|
||||||
os.Clearenv()
|
|
||||||
for _, kv := range args.Env {
|
|
||||||
parts := strings.SplitN(kv, "=", 2)
|
|
||||||
if len(parts) == 1 {
|
|
||||||
parts = append(parts, "")
|
|
||||||
}
|
|
||||||
os.Setenv(parts[0], parts[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup working directory
|
|
||||||
func setupWorkingDirectory(args *InitArgs) error {
|
|
||||||
if args.WorkDir == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err := syscall.Chdir(args.WorkDir); err != nil {
|
|
||||||
return fmt.Errorf("Unable to change dir to %v: %v", args.WorkDir, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package lxc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/opencontainers/runc/libcontainer/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
func finalizeNamespace(args *InitArgs) error {
|
|
||||||
if err := utils.CloseExecFrom(3); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := setupUser(args.User); err != nil {
|
|
||||||
return fmt.Errorf("setup user %s", err)
|
|
||||||
}
|
|
||||||
if err := setupWorkingDirectory(args); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
// +build !linux
|
|
||||||
|
|
||||||
package lxc
|
|
||||||
|
|
||||||
// InitArgs contains args provided to the init function for a driver
|
|
||||||
type InitArgs struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func finalizeNamespace(args *InitArgs) error {
|
|
||||||
panic("Not supported on this platform")
|
|
||||||
}
|
|
|
@ -1,247 +0,0 @@
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package lxc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/docker/daemon/execdriver"
|
|
||||||
nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template"
|
|
||||||
"github.com/docker/docker/pkg/stringutils"
|
|
||||||
"github.com/opencontainers/runc/libcontainer/label"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LxcTemplate is the template for lxc driver, it's used
|
|
||||||
// to configure LXC.
|
|
||||||
const LxcTemplate = `
|
|
||||||
lxc.network.type = none
|
|
||||||
# root filesystem
|
|
||||||
{{$ROOTFS := .Rootfs}}
|
|
||||||
lxc.rootfs = {{$ROOTFS}}
|
|
||||||
|
|
||||||
# use a dedicated pts for the container (and limit the number of pseudo terminal
|
|
||||||
# available)
|
|
||||||
lxc.pts = 1024
|
|
||||||
|
|
||||||
# disable the main console
|
|
||||||
lxc.console = none
|
|
||||||
|
|
||||||
# no controlling tty at all
|
|
||||||
lxc.tty = 1
|
|
||||||
|
|
||||||
{{if .ProcessConfig.Privileged}}
|
|
||||||
lxc.cgroup.devices.allow = a
|
|
||||||
{{else}}
|
|
||||||
# no implicit access to devices
|
|
||||||
lxc.cgroup.devices.deny = a
|
|
||||||
#Allow the devices passed to us in the AllowedDevices list.
|
|
||||||
{{range $allowedDevice := .AllowedDevices}}
|
|
||||||
lxc.cgroup.devices.allow = {{$allowedDevice.CgroupString}}
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
# standard mount point
|
|
||||||
# Use mnt.putold as per https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/986385
|
|
||||||
lxc.pivotdir = lxc_putold
|
|
||||||
|
|
||||||
# lxc.autodev is not compatible with lxc --device switch
|
|
||||||
lxc.autodev = 0
|
|
||||||
|
|
||||||
# NOTICE: These mounts must be applied within the namespace
|
|
||||||
{{if .ProcessConfig.Privileged}}
|
|
||||||
# WARNING: mounting procfs and/or sysfs read-write is a known attack vector.
|
|
||||||
# See e.g. http://blog.zx2c4.com/749 and https://bit.ly/T9CkqJ
|
|
||||||
# We mount them read-write here, but later, dockerinit will call the Restrict() function to remount them read-only.
|
|
||||||
# We cannot mount them directly read-only, because that would prevent loading AppArmor profiles.
|
|
||||||
lxc.mount.entry = proc {{escapeFstabSpaces $ROOTFS}}/proc proc nosuid,nodev,noexec 0 0
|
|
||||||
lxc.mount.entry = sysfs {{escapeFstabSpaces $ROOTFS}}/sys sysfs nosuid,nodev,noexec 0 0
|
|
||||||
{{if .AppArmor}}
|
|
||||||
lxc.aa_profile = unconfined
|
|
||||||
{{end}}
|
|
||||||
{{else}}
|
|
||||||
# In non-privileged mode, lxc will automatically mount /proc and /sys in readonly mode
|
|
||||||
# for security. See: http://man7.org/linux/man-pages/man5/lxc.container.conf.5.html
|
|
||||||
lxc.mount.auto = proc sys
|
|
||||||
{{if .AppArmorProfile}}
|
|
||||||
lxc.aa_profile = {{.AppArmorProfile}}
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{if .ProcessConfig.Tty}}
|
|
||||||
lxc.mount.entry = {{.ProcessConfig.Console}} {{escapeFstabSpaces $ROOTFS}}/dev/console none bind,rw,create=file 0 0
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
lxc.mount.entry = devpts {{escapeFstabSpaces $ROOTFS}}/dev/pts devpts {{formatMountLabel "newinstance,ptmxmode=0666,nosuid,noexec,create=dir" ""}} 0 0
|
|
||||||
lxc.mount.entry = shm {{escapeFstabSpaces $ROOTFS}}/dev/shm tmpfs {{formatMountLabel "size=65536k,nosuid,nodev,noexec,create=dir" ""}} 0 0
|
|
||||||
|
|
||||||
{{range $value := .Mounts}}
|
|
||||||
{{$createVal := isDirectory $value.Source}}
|
|
||||||
{{if $value.Writable}}
|
|
||||||
lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabSpaces $value.Destination}} none rbind,rw,create={{$createVal}} 0 0
|
|
||||||
{{else}}
|
|
||||||
lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabSpaces $value.Destination}} none rbind,ro,create={{$createVal}} 0 0
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
# limits
|
|
||||||
{{if .Resources}}
|
|
||||||
{{if .Resources.Memory}}
|
|
||||||
lxc.cgroup.memory.limit_in_bytes = {{.Resources.Memory}}
|
|
||||||
{{end}}
|
|
||||||
{{if gt .Resources.MemorySwap 0}}
|
|
||||||
lxc.cgroup.memory.memsw.limit_in_bytes = {{.Resources.MemorySwap}}
|
|
||||||
{{end}}
|
|
||||||
{{if gt .Resources.MemoryReservation 0}}
|
|
||||||
lxc.cgroup.memory.soft_limit_in_bytes = {{.Resources.MemoryReservation}}
|
|
||||||
{{end}}
|
|
||||||
{{if gt .Resources.KernelMemory 0}}
|
|
||||||
lxc.cgroup.memory.kmem.limit_in_bytes = {{.Resources.KernelMemory}}
|
|
||||||
{{end}}
|
|
||||||
{{if .Resources.CPUShares}}
|
|
||||||
lxc.cgroup.cpu.shares = {{.Resources.CPUShares}}
|
|
||||||
{{end}}
|
|
||||||
{{if .Resources.CPUPeriod}}
|
|
||||||
lxc.cgroup.cpu.cfs_period_us = {{.Resources.CPUPeriod}}
|
|
||||||
{{end}}
|
|
||||||
{{if .Resources.CpusetCpus}}
|
|
||||||
lxc.cgroup.cpuset.cpus = {{.Resources.CpusetCpus}}
|
|
||||||
{{end}}
|
|
||||||
{{if .Resources.CpusetMems}}
|
|
||||||
lxc.cgroup.cpuset.mems = {{.Resources.CpusetMems}}
|
|
||||||
{{end}}
|
|
||||||
{{if .Resources.CPUQuota}}
|
|
||||||
lxc.cgroup.cpu.cfs_quota_us = {{.Resources.CPUQuota}}
|
|
||||||
{{end}}
|
|
||||||
{{if .Resources.BlkioWeight}}
|
|
||||||
lxc.cgroup.blkio.weight = {{.Resources.BlkioWeight}}
|
|
||||||
{{end}}
|
|
||||||
{{if .Resources.OomKillDisable}}
|
|
||||||
lxc.cgroup.memory.oom_control = {{.Resources.OomKillDisable}}
|
|
||||||
{{end}}
|
|
||||||
{{if gt .Resources.MemorySwappiness 0}}
|
|
||||||
lxc.cgroup.memory.swappiness = {{.Resources.MemorySwappiness}}
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{if .LxcConfig}}
|
|
||||||
{{range $value := .LxcConfig}}
|
|
||||||
lxc.{{$value}}
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{if .ProcessConfig.Env}}
|
|
||||||
lxc.utsname = {{getHostname .ProcessConfig.Env}}
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{if .ProcessConfig.Privileged}}
|
|
||||||
# No cap values are needed, as lxc is starting in privileged mode
|
|
||||||
{{else}}
|
|
||||||
{{ with keepCapabilities .CapAdd .CapDrop }}
|
|
||||||
{{range .}}
|
|
||||||
lxc.cap.keep = {{.}}
|
|
||||||
{{end}}
|
|
||||||
{{else}}
|
|
||||||
{{ with dropList .CapDrop }}
|
|
||||||
{{range .}}
|
|
||||||
lxc.cap.drop = {{.}}
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
`
|
|
||||||
|
|
||||||
var lxcTemplateCompiled *template.Template
|
|
||||||
|
|
||||||
// Escape spaces in strings according to the fstab documentation, which is the
|
|
||||||
// format for "lxc.mount.entry" lines in lxc.conf. See also "man 5 fstab".
|
|
||||||
func escapeFstabSpaces(field string) string {
|
|
||||||
return strings.Replace(field, " ", "\\040", -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func keepCapabilities(adds []string, drops []string) ([]string, error) {
|
|
||||||
container := nativeTemplate.New()
|
|
||||||
logrus.Debugf("adds %s drops %s\n", adds, drops)
|
|
||||||
caps, err := execdriver.TweakCapabilities(container.Capabilities, adds, drops)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var newCaps []string
|
|
||||||
for _, cap := range caps {
|
|
||||||
logrus.Debugf("cap %s\n", cap)
|
|
||||||
realCap := execdriver.GetCapability(cap)
|
|
||||||
numCap := fmt.Sprintf("%d", realCap.Value)
|
|
||||||
newCaps = append(newCaps, numCap)
|
|
||||||
}
|
|
||||||
|
|
||||||
return newCaps, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func dropList(drops []string) ([]string, error) {
|
|
||||||
if stringutils.InSlice(drops, "all") {
|
|
||||||
var newCaps []string
|
|
||||||
for _, capName := range execdriver.GetAllCapabilities() {
|
|
||||||
cap := execdriver.GetCapability(capName)
|
|
||||||
logrus.Debugf("drop cap %s\n", cap.Key)
|
|
||||||
numCap := fmt.Sprintf("%d", cap.Value)
|
|
||||||
newCaps = append(newCaps, numCap)
|
|
||||||
}
|
|
||||||
return newCaps, nil
|
|
||||||
}
|
|
||||||
return []string{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func isDirectory(source string) string {
|
|
||||||
f, err := os.Stat(source)
|
|
||||||
logrus.Debugf("dir: %s\n", source)
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return "dir"
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if f.IsDir() {
|
|
||||||
return "dir"
|
|
||||||
}
|
|
||||||
return "file"
|
|
||||||
}
|
|
||||||
|
|
||||||
func getLabel(c map[string][]string, name string) string {
|
|
||||||
label := c["label"]
|
|
||||||
for _, l := range label {
|
|
||||||
parts := strings.SplitN(l, "=", 2)
|
|
||||||
if strings.TrimSpace(parts[0]) == name {
|
|
||||||
return strings.TrimSpace(parts[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func getHostname(env []string) string {
|
|
||||||
for _, kv := range env {
|
|
||||||
parts := strings.SplitN(kv, "=", 2)
|
|
||||||
if parts[0] == "HOSTNAME" && len(parts) == 2 {
|
|
||||||
return parts[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
var err error
|
|
||||||
funcMap := template.FuncMap{
|
|
||||||
"escapeFstabSpaces": escapeFstabSpaces,
|
|
||||||
"formatMountLabel": label.FormatMountLabel,
|
|
||||||
"isDirectory": isDirectory,
|
|
||||||
"keepCapabilities": keepCapabilities,
|
|
||||||
"dropList": dropList,
|
|
||||||
"getHostname": getHostname,
|
|
||||||
}
|
|
||||||
lxcTemplateCompiled, err = template.New("lxc").Funcs(funcMap).Parse(LxcTemplate)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,355 +0,0 @@
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package lxc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"math/rand"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/docker/docker/daemon/execdriver"
|
|
||||||
nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template"
|
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
|
||||||
"github.com/syndtr/gocapability/capability"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestLXCConfig(t *testing.T) {
|
|
||||||
root, err := ioutil.TempDir("", "TestLXCConfig")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(root)
|
|
||||||
|
|
||||||
os.MkdirAll(path.Join(root, "containers", "1"), 0777)
|
|
||||||
|
|
||||||
// Memory is allocated randomly for testing
|
|
||||||
r := rand.New(rand.NewSource(time.Now().UTC().UnixNano()))
|
|
||||||
var (
|
|
||||||
memMin = 33554432
|
|
||||||
memMax = 536870912
|
|
||||||
mem = memMin + r.Intn(memMax-memMin)
|
|
||||||
swap = memMax
|
|
||||||
cpuMin = 100
|
|
||||||
cpuMax = 10000
|
|
||||||
cpu = cpuMin + r.Intn(cpuMax-cpuMin)
|
|
||||||
)
|
|
||||||
|
|
||||||
driver, err := NewDriver(root, root, "", false)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
command := &execdriver.Command{
|
|
||||||
CommonCommand: execdriver.CommonCommand{
|
|
||||||
ID: "1",
|
|
||||||
Network: &execdriver.Network{
|
|
||||||
Mtu: 1500,
|
|
||||||
},
|
|
||||||
ProcessConfig: execdriver.ProcessConfig{},
|
|
||||||
Resources: &execdriver.Resources{
|
|
||||||
MemorySwap: int64(swap),
|
|
||||||
CommonResources: execdriver.CommonResources{
|
|
||||||
Memory: int64(mem),
|
|
||||||
CPUShares: int64(cpu),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
AllowedDevices: make([]*configs.Device, 0),
|
|
||||||
}
|
|
||||||
p, err := driver.generateLXCConfig(command)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
grepFile(t, p,
|
|
||||||
fmt.Sprintf("lxc.cgroup.memory.limit_in_bytes = %d", mem))
|
|
||||||
|
|
||||||
grepFile(t, p,
|
|
||||||
fmt.Sprintf("lxc.cgroup.memory.memsw.limit_in_bytes = %d", swap))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCustomLxcConfig(t *testing.T) {
|
|
||||||
root, err := ioutil.TempDir("", "TestCustomLxcConfig")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(root)
|
|
||||||
|
|
||||||
os.MkdirAll(path.Join(root, "containers", "1"), 0777)
|
|
||||||
|
|
||||||
driver, err := NewDriver(root, root, "", false)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
processConfig := execdriver.ProcessConfig{
|
|
||||||
Privileged: false,
|
|
||||||
}
|
|
||||||
command := &execdriver.Command{
|
|
||||||
CommonCommand: execdriver.CommonCommand{
|
|
||||||
ID: "1",
|
|
||||||
Network: &execdriver.Network{
|
|
||||||
Mtu: 1500,
|
|
||||||
},
|
|
||||||
ProcessConfig: processConfig,
|
|
||||||
},
|
|
||||||
LxcConfig: []string{
|
|
||||||
"lxc.utsname = docker",
|
|
||||||
"lxc.cgroup.cpuset.cpus = 0,1",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
p, err := driver.generateLXCConfig(command)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
grepFile(t, p, "lxc.utsname = docker")
|
|
||||||
grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
|
|
||||||
}
|
|
||||||
|
|
||||||
func grepFile(t *testing.T, path string, pattern string) {
|
|
||||||
grepFileWithReverse(t, path, pattern, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func grepFileWithReverse(t *testing.T, path string, pattern string, inverseGrep bool) {
|
|
||||||
f, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
r := bufio.NewReader(f)
|
|
||||||
var (
|
|
||||||
line string
|
|
||||||
)
|
|
||||||
err = nil
|
|
||||||
for err == nil {
|
|
||||||
line, err = r.ReadString('\n')
|
|
||||||
if strings.Contains(line, pattern) == true {
|
|
||||||
if inverseGrep {
|
|
||||||
t.Fatalf("grepFile: pattern \"%s\" found in \"%s\"", pattern, path)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if inverseGrep {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.Fatalf("grepFile: pattern \"%s\" not found in \"%s\"", pattern, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEscapeFstabSpaces(t *testing.T) {
|
|
||||||
var testInputs = map[string]string{
|
|
||||||
" ": "\\040",
|
|
||||||
"": "",
|
|
||||||
"/double space": "/double\\040\\040space",
|
|
||||||
"/some long test string": "/some\\040long\\040test\\040string",
|
|
||||||
"/var/lib/docker": "/var/lib/docker",
|
|
||||||
" leading": "\\040leading",
|
|
||||||
"trailing ": "trailing\\040",
|
|
||||||
}
|
|
||||||
for in, exp := range testInputs {
|
|
||||||
if out := escapeFstabSpaces(in); exp != out {
|
|
||||||
t.Logf("Expected %s got %s", exp, out)
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsDirectory(t *testing.T) {
|
|
||||||
tempDir, err := ioutil.TempDir("", "TestIsDir")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(tempDir)
|
|
||||||
|
|
||||||
tempFile, err := ioutil.TempFile(tempDir, "TestIsDirFile")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if isDirectory(tempDir) != "dir" {
|
|
||||||
t.Logf("Could not identify %s as a directory", tempDir)
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
|
|
||||||
if isDirectory(tempFile.Name()) != "file" {
|
|
||||||
t.Logf("Could not identify %s as a file", tempFile.Name())
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCustomLxcConfigMounts(t *testing.T) {
|
|
||||||
root, err := ioutil.TempDir("", "TestCustomLxcConfig")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(root)
|
|
||||||
tempDir, err := ioutil.TempDir("", "TestIsDir")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(tempDir)
|
|
||||||
|
|
||||||
tempFile, err := ioutil.TempFile(tempDir, "TestIsDirFile")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
os.MkdirAll(path.Join(root, "containers", "1"), 0777)
|
|
||||||
|
|
||||||
driver, err := NewDriver(root, root, "", false)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
processConfig := execdriver.ProcessConfig{
|
|
||||||
Privileged: false,
|
|
||||||
}
|
|
||||||
mounts := []execdriver.Mount{
|
|
||||||
{
|
|
||||||
Source: tempDir,
|
|
||||||
Destination: tempDir,
|
|
||||||
Writable: false,
|
|
||||||
Private: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Source: tempFile.Name(),
|
|
||||||
Destination: tempFile.Name(),
|
|
||||||
Writable: true,
|
|
||||||
Private: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
command := &execdriver.Command{
|
|
||||||
CommonCommand: execdriver.CommonCommand{
|
|
||||||
ID: "1",
|
|
||||||
Network: &execdriver.Network{
|
|
||||||
Mtu: 1500,
|
|
||||||
},
|
|
||||||
Mounts: mounts,
|
|
||||||
ProcessConfig: processConfig,
|
|
||||||
},
|
|
||||||
LxcConfig: []string{
|
|
||||||
"lxc.utsname = docker",
|
|
||||||
"lxc.cgroup.cpuset.cpus = 0,1",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
p, err := driver.generateLXCConfig(command)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
grepFile(t, p, "lxc.utsname = docker")
|
|
||||||
grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
|
|
||||||
|
|
||||||
grepFile(t, p, fmt.Sprintf("lxc.mount.entry = %s %s none rbind,ro,create=%s 0 0", tempDir, "/"+tempDir, "dir"))
|
|
||||||
grepFile(t, p, fmt.Sprintf("lxc.mount.entry = %s %s none rbind,rw,create=%s 0 0", tempFile.Name(), "/"+tempFile.Name(), "file"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCustomLxcConfigMisc(t *testing.T) {
|
|
||||||
root, err := ioutil.TempDir("", "TestCustomLxcConfig")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(root)
|
|
||||||
os.MkdirAll(path.Join(root, "containers", "1"), 0777)
|
|
||||||
driver, err := NewDriver(root, root, "", true)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
processConfig := execdriver.ProcessConfig{
|
|
||||||
Privileged: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
processConfig.Env = []string{"HOSTNAME=testhost"}
|
|
||||||
command := &execdriver.Command{
|
|
||||||
CommonCommand: execdriver.CommonCommand{
|
|
||||||
ID: "1",
|
|
||||||
Network: &execdriver.Network{
|
|
||||||
Mtu: 1500,
|
|
||||||
},
|
|
||||||
ProcessConfig: processConfig,
|
|
||||||
},
|
|
||||||
LxcConfig: []string{
|
|
||||||
"lxc.cgroup.cpuset.cpus = 0,1",
|
|
||||||
},
|
|
||||||
CapAdd: []string{"net_admin", "syslog"},
|
|
||||||
CapDrop: []string{"kill", "mknod"},
|
|
||||||
AppArmorProfile: "lxc-container-default-with-nesting",
|
|
||||||
}
|
|
||||||
|
|
||||||
p, err := driver.generateLXCConfig(command)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
grepFile(t, p, "lxc.aa_profile = lxc-container-default-with-nesting")
|
|
||||||
// hostname
|
|
||||||
grepFile(t, p, "lxc.utsname = testhost")
|
|
||||||
grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
|
|
||||||
container := nativeTemplate.New()
|
|
||||||
for _, cap := range container.Capabilities {
|
|
||||||
realCap := execdriver.GetCapability(cap)
|
|
||||||
numCap := fmt.Sprintf("%d", realCap.Value)
|
|
||||||
if cap != "MKNOD" && cap != "KILL" {
|
|
||||||
grepFile(t, p, fmt.Sprintf("lxc.cap.keep = %s", numCap))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_KILL), true)
|
|
||||||
grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_MKNOD), true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCustomLxcConfigMiscOverride(t *testing.T) {
|
|
||||||
root, err := ioutil.TempDir("", "TestCustomLxcConfig")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(root)
|
|
||||||
os.MkdirAll(path.Join(root, "containers", "1"), 0777)
|
|
||||||
driver, err := NewDriver(root, root, "", false)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
processConfig := execdriver.ProcessConfig{
|
|
||||||
Privileged: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
processConfig.Env = []string{"HOSTNAME=testhost"}
|
|
||||||
command := &execdriver.Command{
|
|
||||||
CommonCommand: execdriver.CommonCommand{
|
|
||||||
ID: "1",
|
|
||||||
Network: &execdriver.Network{
|
|
||||||
Mtu: 1500,
|
|
||||||
},
|
|
||||||
ProcessConfig: processConfig,
|
|
||||||
},
|
|
||||||
LxcConfig: []string{
|
|
||||||
"lxc.cgroup.cpuset.cpus = 0,1",
|
|
||||||
"lxc.network.ipv4 = 172.0.0.1",
|
|
||||||
},
|
|
||||||
CapAdd: []string{"NET_ADMIN", "SYSLOG"},
|
|
||||||
CapDrop: []string{"KILL", "MKNOD"},
|
|
||||||
}
|
|
||||||
|
|
||||||
p, err := driver.generateLXCConfig(command)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// hostname
|
|
||||||
grepFile(t, p, "lxc.utsname = testhost")
|
|
||||||
grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
|
|
||||||
container := nativeTemplate.New()
|
|
||||||
for _, cap := range container.Capabilities {
|
|
||||||
realCap := execdriver.GetCapability(cap)
|
|
||||||
numCap := fmt.Sprintf("%d", realCap.Value)
|
|
||||||
if cap != "MKNOD" && cap != "KILL" {
|
|
||||||
grepFile(t, p, fmt.Sprintf("lxc.cap.keep = %s", numCap))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_KILL), true)
|
|
||||||
grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_MKNOD), true)
|
|
||||||
}
|
|
|
@ -1504,7 +1504,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// It seems libdevmapper opens this without O_CLOEXEC, and go exec will not close files
|
// It seems libdevmapper opens this without O_CLOEXEC, and go exec will not close files
|
||||||
// that are not Close-on-exec, and lxc-start will die if it inherits any unexpected files,
|
// that are not Close-on-exec,
|
||||||
// so we add this badhack to make sure it closes itself
|
// so we add this badhack to make sure it closes itself
|
||||||
setCloseOnExec("/dev/mapper/control")
|
setCloseOnExec("/dev/mapper/control")
|
||||||
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
package daemon
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/docker/docker/runconfig"
|
|
||||||
)
|
|
||||||
|
|
||||||
func mergeLxcConfIntoOptions(hostConfig *runconfig.HostConfig) ([]string, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
|
@ -2,14 +2,7 @@
|
||||||
|
|
||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import "github.com/opencontainers/runc/libcontainer/selinux"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/docker/runconfig"
|
|
||||||
"github.com/opencontainers/runc/libcontainer/selinux"
|
|
||||||
)
|
|
||||||
|
|
||||||
func selinuxSetDisabled() {
|
func selinuxSetDisabled() {
|
||||||
selinux.SetDisabled()
|
selinux.SetDisabled()
|
||||||
|
@ -22,27 +15,3 @@ func selinuxFreeLxcContexts(label string) {
|
||||||
func selinuxEnabled() bool {
|
func selinuxEnabled() bool {
|
||||||
return selinux.SelinuxEnabled()
|
return selinux.SelinuxEnabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
func mergeLxcConfIntoOptions(hostConfig *runconfig.HostConfig) ([]string, error) {
|
|
||||||
if hostConfig == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
out := []string{}
|
|
||||||
|
|
||||||
// merge in the lxc conf options into the generic config map
|
|
||||||
if lxcConf := hostConfig.LxcConf; lxcConf != nil {
|
|
||||||
lxSlice := lxcConf.Slice()
|
|
||||||
for _, pair := range lxSlice {
|
|
||||||
// because lxc conf gets the driver name lxc.XXXX we need to trim it off
|
|
||||||
// and let the lxc driver add it back later if needed
|
|
||||||
if !strings.Contains(pair.Key, ".") {
|
|
||||||
return nil, errors.New("Illegal Key passed into LXC Configurations")
|
|
||||||
}
|
|
||||||
parts := strings.SplitN(pair.Key, ".", 2)
|
|
||||||
out = append(out, fmt.Sprintf("%s=%s", parts[1], pair.Value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package daemon
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/docker/docker/runconfig"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMergeLxcConfig(t *testing.T) {
|
|
||||||
kv := []runconfig.KeyValuePair{
|
|
||||||
{"lxc.cgroups.cpuset", "1,2"},
|
|
||||||
}
|
|
||||||
hostConfig := &runconfig.HostConfig{
|
|
||||||
LxcConf: runconfig.NewLxcConfig(kv),
|
|
||||||
}
|
|
||||||
|
|
||||||
out, err := mergeLxcConfIntoOptions(hostConfig)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to merge Lxc Config: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cpuset := out[0]
|
|
||||||
if expected := "cgroups.cpuset=1,2"; cpuset != expected {
|
|
||||||
t.Fatalf("expected %s got %s", expected, cpuset)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
systemdDaemon "github.com/coreos/go-systemd/daemon"
|
systemdDaemon "github.com/coreos/go-systemd/daemon"
|
||||||
_ "github.com/docker/docker/daemon/execdriver/lxc"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// notifySystem sends a message to the host when the server is ready to be used
|
// notifySystem sends a message to the host when the server is ready to be used
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "github.com/docker/docker/daemon/execdriver/lxc"
|
|
||||||
_ "github.com/docker/docker/daemon/execdriver/native"
|
_ "github.com/docker/docker/daemon/execdriver/native"
|
||||||
"github.com/docker/docker/pkg/reexec"
|
"github.com/docker/docker/pkg/reexec"
|
||||||
)
|
)
|
||||||
|
|
|
@ -212,7 +212,6 @@ recommendations.
|
||||||
dpkg-sig \
|
dpkg-sig \
|
||||||
libcap-dev \
|
libcap-dev \
|
||||||
libsqlite3-dev \
|
libsqlite3-dev \
|
||||||
lxc=1.0* \
|
|
||||||
mercurial \
|
mercurial \
|
||||||
reprepro \
|
reprepro \
|
||||||
ruby1.9.1 \
|
ruby1.9.1 \
|
||||||
|
|
|
@ -29,7 +29,6 @@ in the packages. The core dependencies are:
|
||||||
- bridge-utils
|
- bridge-utils
|
||||||
- device-mapper
|
- device-mapper
|
||||||
- iproute2
|
- iproute2
|
||||||
- lxc
|
|
||||||
- sqlite
|
- sqlite
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
|
@ -50,7 +50,6 @@ IRC channel on the Freenode network.
|
||||||
| contrib | Yes |Install additional contributed scripts and components.|
|
| contrib | Yes |Install additional contributed scripts and components.|
|
||||||
| device-mapper | Yes |Enables dependencies for the "devicemapper" graph driver, including necessary kernel flags.|
|
| device-mapper | Yes |Enables dependencies for the "devicemapper" graph driver, including necessary kernel flags.|
|
||||||
| doc | |Add extra documentation (API, Javadoc, etc). It is recommended to enable per package instead of globally.|
|
| doc | |Add extra documentation (API, Javadoc, etc). It is recommended to enable per package instead of globally.|
|
||||||
| lxc | |Enables dependencies for the "lxc" execution driver.|
|
|
||||||
| vim-syntax | |Pulls in related vim syntax scripts.|
|
| vim-syntax | |Pulls in related vim syntax scripts.|
|
||||||
| zsh-completion| |Enable zsh completion support.|
|
| zsh-completion| |Enable zsh completion support.|
|
||||||
|
|
||||||
|
|
|
@ -174,7 +174,6 @@ Create a container
|
||||||
"HostConfig": {
|
"HostConfig": {
|
||||||
"Binds": ["/tmp:/tmp"],
|
"Binds": ["/tmp:/tmp"],
|
||||||
"Links": ["redis3:redis"],
|
"Links": ["redis3:redis"],
|
||||||
"LxcConf": {"lxc.utsname":"docker"},
|
|
||||||
"Memory": 0,
|
"Memory": 0,
|
||||||
"MemorySwap": 0,
|
"MemorySwap": 0,
|
||||||
"MemoryReservation": 0,
|
"MemoryReservation": 0,
|
||||||
|
@ -270,8 +269,6 @@ Json Parameters:
|
||||||
+ `volume_name:container_path:ro` to make the bind mount read-only inside the container.
|
+ `volume_name:container_path:ro` to make the bind mount read-only inside the container.
|
||||||
- **Links** - A list of links for the container. Each link entry should be
|
- **Links** - A list of links for the container. Each link entry should be
|
||||||
in the form of `container_name:alias`.
|
in the form of `container_name:alias`.
|
||||||
- **LxcConf** - LXC specific configurations. These configurations only
|
|
||||||
work when using the `lxc` execution driver.
|
|
||||||
- **PortBindings** - A map of exposed container ports and the host port they
|
- **PortBindings** - A map of exposed container ports and the host port they
|
||||||
should map to. A JSON object in the form
|
should map to. A JSON object in the form
|
||||||
`{ <port>/<protocol>: [{ "HostPort": "<port>" }] }`
|
`{ <port>/<protocol>: [{ "HostPort": "<port>" }] }`
|
||||||
|
|
|
@ -48,7 +48,6 @@ Creates a new container.
|
||||||
--link=[] Add link to another container
|
--link=[] Add link to another container
|
||||||
--log-driver="" Logging driver for container
|
--log-driver="" Logging driver for container
|
||||||
--log-opt=[] Log driver specific options
|
--log-opt=[] Log driver specific options
|
||||||
--lxc-conf=[] Add custom lxc options
|
|
||||||
-m, --memory="" Memory limit
|
-m, --memory="" Memory limit
|
||||||
--mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33)
|
--mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33)
|
||||||
--memory-reservation="" Memory soft limit
|
--memory-reservation="" Memory soft limit
|
||||||
|
|
|
@ -439,11 +439,6 @@ Currently supported options of `zfs`:
|
||||||
The Docker daemon uses a specifically built `libcontainer` execution driver as
|
The Docker daemon uses a specifically built `libcontainer` execution driver as
|
||||||
its interface to the Linux kernel `namespaces`, `cgroups`, and `SELinux`.
|
its interface to the Linux kernel `namespaces`, `cgroups`, and `SELinux`.
|
||||||
|
|
||||||
There is still legacy support for the original [LXC userspace tools](
|
|
||||||
https://linuxcontainers.org/) via the `lxc` execution driver, however, this is
|
|
||||||
not where the primary development of new functionality is taking place.
|
|
||||||
Add `-e lxc` to the daemon flags to use the `lxc` execution driver.
|
|
||||||
|
|
||||||
## Options for the native execdriver
|
## Options for the native execdriver
|
||||||
|
|
||||||
You can configure the `native` (libcontainer) execdriver using options specified
|
You can configure the `native` (libcontainer) execdriver using options specified
|
||||||
|
|
|
@ -47,7 +47,6 @@ parent = "smn_cli"
|
||||||
--link=[] Add link to another container
|
--link=[] Add link to another container
|
||||||
--log-driver="" Logging driver for container
|
--log-driver="" Logging driver for container
|
||||||
--log-opt=[] Log driver specific options
|
--log-opt=[] Log driver specific options
|
||||||
--lxc-conf=[] Add custom lxc options
|
|
||||||
-m, --memory="" Memory limit
|
-m, --memory="" Memory limit
|
||||||
--mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33)
|
--mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33)
|
||||||
--memory-reservation="" Memory soft limit
|
--memory-reservation="" Memory soft limit
|
||||||
|
|
|
@ -39,7 +39,6 @@ defaults related to:
|
||||||
* container identification
|
* container identification
|
||||||
* network settings
|
* network settings
|
||||||
* runtime constraints on CPU and memory
|
* runtime constraints on CPU and memory
|
||||||
* privileges and LXC configuration
|
|
||||||
|
|
||||||
With the `docker run [OPTIONS]` an operator can add to or override the
|
With the `docker run [OPTIONS]` an operator can add to or override the
|
||||||
image defaults set by a developer. And, additionally, operators can
|
image defaults set by a developer. And, additionally, operators can
|
||||||
|
@ -75,7 +74,7 @@ following options.
|
||||||
- [Restart policies (--restart)](#restart-policies-restart)
|
- [Restart policies (--restart)](#restart-policies-restart)
|
||||||
- [Clean up (--rm)](#clean-up-rm)
|
- [Clean up (--rm)](#clean-up-rm)
|
||||||
- [Runtime constraints on resources](#runtime-constraints-on-resources)
|
- [Runtime constraints on resources](#runtime-constraints-on-resources)
|
||||||
- [Runtime privilege, Linux capabilities, and LXC configuration](#runtime-privilege-linux-capabilities-and-lxc-configuration)
|
- [Runtime privilege and Linux capabilities](#runtime-privilege-and-linux-capabilities)
|
||||||
|
|
||||||
## Detached vs foreground
|
## Detached vs foreground
|
||||||
|
|
||||||
|
@ -933,21 +932,18 @@ one can use this flag:
|
||||||
$ docker run -ti --rm --group-add audio --group-add dbus --group-add 777 busybox id
|
$ docker run -ti --rm --group-add audio --group-add dbus --group-add 777 busybox id
|
||||||
uid=0(root) gid=0(root) groups=10(wheel),29(audio),81(dbus),777
|
uid=0(root) gid=0(root) groups=10(wheel),29(audio),81(dbus),777
|
||||||
|
|
||||||
## Runtime privilege, Linux capabilities, and LXC configuration
|
## Runtime privilege and Linux capabilities
|
||||||
|
|
||||||
--cap-add: Add Linux capabilities
|
--cap-add: Add Linux capabilities
|
||||||
--cap-drop: Drop Linux capabilities
|
--cap-drop: Drop Linux capabilities
|
||||||
--privileged=false: Give extended privileges to this container
|
--privileged=false: Give extended privileges to this container
|
||||||
--device=[]: Allows you to run devices inside the container without the --privileged flag.
|
--device=[]: Allows you to run devices inside the container without the --privileged flag.
|
||||||
--lxc-conf=[]: Add custom lxc options
|
|
||||||
|
|
||||||
By default, Docker containers are "unprivileged" and cannot, for
|
By default, Docker containers are "unprivileged" and cannot, for
|
||||||
example, run a Docker daemon inside a Docker container. This is because
|
example, run a Docker daemon inside a Docker container. This is because
|
||||||
by default a container is not allowed to access any devices, but a
|
by default a container is not allowed to access any devices, but a
|
||||||
"privileged" container is given access to all devices (see [lxc-template.go](
|
"privileged" container is given access to all devices (see
|
||||||
https://github.com/docker/docker/blob/master/daemon/execdriver/lxc/lxc_template.go)
|
the documentation on [cgroups devices](https://www.kernel.org/doc/Documentation/cgroups/devices.txt)).
|
||||||
and documentation on [cgroups devices](
|
|
||||||
https://www.kernel.org/doc/Documentation/cgroups/devices.txt)).
|
|
||||||
|
|
||||||
When the operator executes `docker run --privileged`, Docker will enable
|
When the operator executes `docker run --privileged`, Docker will enable
|
||||||
to access to all devices on the host as well as set some configuration
|
to access to all devices on the host as well as set some configuration
|
||||||
|
@ -1061,22 +1057,6 @@ To mount a FUSE based filesystem, you need to combine both `--cap-add` and
|
||||||
....
|
....
|
||||||
|
|
||||||
|
|
||||||
If the Docker daemon was started using the `lxc` exec-driver
|
|
||||||
(`docker daemon --exec-driver=lxc`) then the operator can also specify LXC options
|
|
||||||
using one or more `--lxc-conf` parameters. These can be new parameters or
|
|
||||||
override existing parameters from the [lxc-template.go](
|
|
||||||
https://github.com/docker/docker/blob/master/daemon/execdriver/lxc/lxc_template.go).
|
|
||||||
Note that in the future, a given host's docker daemon may not use LXC, so this
|
|
||||||
is an implementation-specific configuration meant for operators already
|
|
||||||
familiar with using LXC directly.
|
|
||||||
|
|
||||||
> **Note:**
|
|
||||||
> If you use `--lxc-conf` to modify a container's configuration which is also
|
|
||||||
> managed by the Docker daemon, then the Docker daemon will not know about this
|
|
||||||
> modification, and you will need to manage any conflicts yourself. For example,
|
|
||||||
> you can use `--lxc-conf` to set a container's IP address, but this will not be
|
|
||||||
> reflected in the `/etc/hosts` file.
|
|
||||||
|
|
||||||
## Logging drivers (--log-driver)
|
## Logging drivers (--log-driver)
|
||||||
|
|
||||||
The container can have a different logging driver than the Docker daemon. Use
|
The container can have a different logging driver than the Docker daemon. Use
|
||||||
|
@ -1258,7 +1238,6 @@ above, or already defined by the developer with a Dockerfile `ENV`:
|
||||||
declare -x PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
declare -x PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||||
declare -x PWD="/"
|
declare -x PWD="/"
|
||||||
declare -x SHLVL="1"
|
declare -x SHLVL="1"
|
||||||
declare -x container="lxc"
|
|
||||||
declare -x deep="purple"
|
declare -x deep="purple"
|
||||||
|
|
||||||
Similarly the operator can set the **hostname** with `-h`.
|
Similarly the operator can set the **hostname** with `-h`.
|
||||||
|
|
|
@ -109,7 +109,6 @@ running a Docker daemon with experimental user namespaces enabled:
|
||||||
- A `--readonly` container filesystem (a Linux kernel restriction on remount with new flags of a currently mounted filesystem when inside a user namespace)
|
- A `--readonly` container filesystem (a Linux kernel restriction on remount with new flags of a currently mounted filesystem when inside a user namespace)
|
||||||
- external (volume/graph) drivers which are unaware/incapable of using daemon user mappings
|
- external (volume/graph) drivers which are unaware/incapable of using daemon user mappings
|
||||||
- Using `--privileged` mode containers
|
- Using `--privileged` mode containers
|
||||||
- Using the lxc execdriver (only the `native` execdriver is enabled to use user namespaces)
|
|
||||||
- volume use without pre-arranging proper file ownership in mounted volumes
|
- volume use without pre-arranging proper file ownership in mounted volumes
|
||||||
|
|
||||||
Additionally, while the `root` user inside a user namespaced container
|
Additionally, while the `root` user inside a user namespaced container
|
||||||
|
|
|
@ -31,13 +31,6 @@ if ! mountpoint -q /sys/fs/cgroup; then
|
||||||
# Mount the cgroup hierarchies exactly as they are in the parent system.
|
# Mount the cgroup hierarchies exactly as they are in the parent system.
|
||||||
for HIER in $(cut -d: -f2 /proc/1/cgroup); do
|
for HIER in $(cut -d: -f2 /proc/1/cgroup); do
|
||||||
|
|
||||||
# The following sections address a bug which manifests itself
|
|
||||||
# by a cryptic "lxc-start: no ns_cgroup option specified" when
|
|
||||||
# trying to start containers within a container.
|
|
||||||
# The bug seems to appear when the cgroup hierarchies are not
|
|
||||||
# mounted on the exact same directories in the host, and in the
|
|
||||||
# container.
|
|
||||||
|
|
||||||
SUBSYSTEMS="${HIER%name=*}"
|
SUBSYSTEMS="${HIER%name=*}"
|
||||||
|
|
||||||
# If cgroup hierarchy is named(mounted with "-o name=foo") we
|
# If cgroup hierarchy is named(mounted with "-o name=foo") we
|
||||||
|
|
|
@ -109,10 +109,6 @@ if [ -z "$DOCKER_CLIENTONLY" ]; then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$DOCKER_EXECDRIVER" = 'lxc' ]; then
|
|
||||||
DOCKER_BUILDTAGS+=' test_no_exec'
|
|
||||||
fi
|
|
||||||
|
|
||||||
# test whether "btrfs/version.h" exists and apply btrfs_noversion appropriately
|
# test whether "btrfs/version.h" exists and apply btrfs_noversion appropriately
|
||||||
if \
|
if \
|
||||||
command -v gcc &> /dev/null \
|
command -v gcc &> /dev/null \
|
||||||
|
|
|
@ -58,8 +58,8 @@ func (s *DockerSuite) TestDiffEnsureOnlyKmsgAndPtmx(c *check.C) {
|
||||||
"C /dev": true,
|
"C /dev": true,
|
||||||
"A /dev/full": true, // busybox
|
"A /dev/full": true, // busybox
|
||||||
"C /dev/ptmx": true, // libcontainer
|
"C /dev/ptmx": true, // libcontainer
|
||||||
"A /dev/mqueue": true, // lxc
|
"A /dev/mqueue": true,
|
||||||
"A /dev/kmsg": true, // lxc
|
"A /dev/kmsg": true,
|
||||||
"A /dev/fd": true,
|
"A /dev/fd": true,
|
||||||
"A /dev/fuse": true,
|
"A /dev/fuse": true,
|
||||||
"A /dev/ptmx": true,
|
"A /dev/ptmx": true,
|
||||||
|
|
|
@ -66,13 +66,11 @@ func (s *DockerSuite) TestRunLookupGoogleDns(c *check.C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// the exit code should be 0
|
// the exit code should be 0
|
||||||
// some versions of lxc might make this test fail
|
|
||||||
func (s *DockerSuite) TestRunExitCodeZero(c *check.C) {
|
func (s *DockerSuite) TestRunExitCodeZero(c *check.C) {
|
||||||
dockerCmd(c, "run", "busybox", "true")
|
dockerCmd(c, "run", "busybox", "true")
|
||||||
}
|
}
|
||||||
|
|
||||||
// the exit code should be 1
|
// the exit code should be 1
|
||||||
// some versions of lxc might make this test fail
|
|
||||||
func (s *DockerSuite) TestRunExitCodeOne(c *check.C) {
|
func (s *DockerSuite) TestRunExitCodeOne(c *check.C) {
|
||||||
_, exitCode, err := dockerCmdWithError("run", "busybox", "false")
|
_, exitCode, err := dockerCmdWithError("run", "busybox", "false")
|
||||||
if err != nil && !strings.Contains("exit status 1", fmt.Sprintf("%s", err)) {
|
if err != nil && !strings.Contains("exit status 1", fmt.Sprintf("%s", err)) {
|
||||||
|
@ -84,7 +82,6 @@ func (s *DockerSuite) TestRunExitCodeOne(c *check.C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// it should be possible to pipe in data via stdin to a process running in a container
|
// it should be possible to pipe in data via stdin to a process running in a container
|
||||||
// some versions of lxc might make this test fail
|
|
||||||
func (s *DockerSuite) TestRunStdinPipe(c *check.C) {
|
func (s *DockerSuite) TestRunStdinPipe(c *check.C) {
|
||||||
// TODO Windows: This needs some work to make compatible.
|
// TODO Windows: This needs some work to make compatible.
|
||||||
testRequires(c, DaemonIsLinux)
|
testRequires(c, DaemonIsLinux)
|
||||||
|
@ -664,7 +661,7 @@ func (s *DockerSuite) TestRunTwoConcurrentContainers(c *check.C) {
|
||||||
|
|
||||||
func (s *DockerSuite) TestRunEnvironment(c *check.C) {
|
func (s *DockerSuite) TestRunEnvironment(c *check.C) {
|
||||||
// TODO Windows: Environment handling is different between Linux and
|
// TODO Windows: Environment handling is different between Linux and
|
||||||
// Windows and this test relies currently on lxc and unix functionality.
|
// Windows and this test relies currently on unix functionality.
|
||||||
testRequires(c, DaemonIsLinux)
|
testRequires(c, DaemonIsLinux)
|
||||||
cmd := exec.Command(dockerBinary, "run", "-h", "testing", "-e=FALSE=true", "-e=TRUE", "-e=TRICKY", "-e=HOME=", "busybox", "env")
|
cmd := exec.Command(dockerBinary, "run", "-h", "testing", "-e=FALSE=true", "-e=TRUE", "-e=TRICKY", "-e=HOME=", "busybox", "env")
|
||||||
cmd.Env = append(os.Environ(),
|
cmd.Env = append(os.Environ(),
|
||||||
|
@ -677,13 +674,7 @@ func (s *DockerSuite) TestRunEnvironment(c *check.C) {
|
||||||
c.Fatal(err, out)
|
c.Fatal(err, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
actualEnvLxc := strings.Split(strings.TrimSpace(out), "\n")
|
actualEnv := strings.Split(strings.TrimSpace(out), "\n")
|
||||||
actualEnv := []string{}
|
|
||||||
for i := range actualEnvLxc {
|
|
||||||
if actualEnvLxc[i] != "container=lxc" {
|
|
||||||
actualEnv = append(actualEnv, actualEnvLxc[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Strings(actualEnv)
|
sort.Strings(actualEnv)
|
||||||
|
|
||||||
goodEnv := []string{
|
goodEnv := []string{
|
||||||
|
@ -709,7 +700,7 @@ func (s *DockerSuite) TestRunEnvironment(c *check.C) {
|
||||||
|
|
||||||
func (s *DockerSuite) TestRunEnvironmentErase(c *check.C) {
|
func (s *DockerSuite) TestRunEnvironmentErase(c *check.C) {
|
||||||
// TODO Windows: Environment handling is different between Linux and
|
// TODO Windows: Environment handling is different between Linux and
|
||||||
// Windows and this test relies currently on lxc and unix functionality.
|
// Windows and this test relies currently on unix functionality.
|
||||||
testRequires(c, DaemonIsLinux)
|
testRequires(c, DaemonIsLinux)
|
||||||
|
|
||||||
// Test to make sure that when we use -e on env vars that are
|
// Test to make sure that when we use -e on env vars that are
|
||||||
|
@ -724,13 +715,7 @@ func (s *DockerSuite) TestRunEnvironmentErase(c *check.C) {
|
||||||
c.Fatal(err, out)
|
c.Fatal(err, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
actualEnvLxc := strings.Split(strings.TrimSpace(out), "\n")
|
actualEnv := strings.Split(strings.TrimSpace(out), "\n")
|
||||||
actualEnv := []string{}
|
|
||||||
for i := range actualEnvLxc {
|
|
||||||
if actualEnvLxc[i] != "container=lxc" {
|
|
||||||
actualEnv = append(actualEnv, actualEnvLxc[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Strings(actualEnv)
|
sort.Strings(actualEnv)
|
||||||
|
|
||||||
goodEnv := []string{
|
goodEnv := []string{
|
||||||
|
@ -750,7 +735,7 @@ func (s *DockerSuite) TestRunEnvironmentErase(c *check.C) {
|
||||||
|
|
||||||
func (s *DockerSuite) TestRunEnvironmentOverride(c *check.C) {
|
func (s *DockerSuite) TestRunEnvironmentOverride(c *check.C) {
|
||||||
// TODO Windows: Environment handling is different between Linux and
|
// TODO Windows: Environment handling is different between Linux and
|
||||||
// Windows and this test relies currently on lxc and unix functionality.
|
// Windows and this test relies currently on unix functionality.
|
||||||
testRequires(c, DaemonIsLinux)
|
testRequires(c, DaemonIsLinux)
|
||||||
|
|
||||||
// Test to make sure that when we use -e on env vars that are
|
// Test to make sure that when we use -e on env vars that are
|
||||||
|
@ -764,13 +749,7 @@ func (s *DockerSuite) TestRunEnvironmentOverride(c *check.C) {
|
||||||
c.Fatal(err, out)
|
c.Fatal(err, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
actualEnvLxc := strings.Split(strings.TrimSpace(out), "\n")
|
actualEnv := strings.Split(strings.TrimSpace(out), "\n")
|
||||||
actualEnv := []string{}
|
|
||||||
for i := range actualEnvLxc {
|
|
||||||
if actualEnvLxc[i] != "container=lxc" {
|
|
||||||
actualEnv = append(actualEnv, actualEnvLxc[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Strings(actualEnv)
|
sort.Strings(actualEnv)
|
||||||
|
|
||||||
goodEnv := []string{
|
goodEnv := []string{
|
||||||
|
|
|
@ -17,7 +17,6 @@ import (
|
||||||
"github.com/docker/docker/pkg/mount"
|
"github.com/docker/docker/pkg/mount"
|
||||||
"github.com/docker/docker/pkg/parsers"
|
"github.com/docker/docker/pkg/parsers"
|
||||||
"github.com/docker/docker/pkg/sysinfo"
|
"github.com/docker/docker/pkg/sysinfo"
|
||||||
"github.com/docker/docker/pkg/units"
|
|
||||||
"github.com/go-check/check"
|
"github.com/go-check/check"
|
||||||
"github.com/kr/pty"
|
"github.com/kr/pty"
|
||||||
)
|
)
|
||||||
|
@ -437,22 +436,3 @@ func (s *DockerSuite) TestRunInvalidCPUShares(c *check.C) {
|
||||||
expected = "The maximum allowed cpu-shares is"
|
expected = "The maximum allowed cpu-shares is"
|
||||||
c.Assert(out, checker.Contains, expected)
|
c.Assert(out, checker.Contains, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DockerSuite) TestRunWithCorrectMemorySwapOnLXC(c *check.C) {
|
|
||||||
testRequires(c, memoryLimitSupport)
|
|
||||||
testRequires(c, swapMemorySupport)
|
|
||||||
testRequires(c, SameHostDaemon)
|
|
||||||
|
|
||||||
out, _ := dockerCmd(c, "run", "-d", "-m", "32m", "--memory-swap", "64m", "busybox", "top")
|
|
||||||
if _, err := os.Stat("/sys/fs/cgroup/memory/lxc"); err != nil {
|
|
||||||
c.Skip("Excecution driver must be LXC for this test")
|
|
||||||
}
|
|
||||||
id := strings.TrimSpace(out)
|
|
||||||
memorySwap, err := ioutil.ReadFile(fmt.Sprintf("/sys/fs/cgroup/memory/lxc/%s/memory.memsw.limit_in_bytes", id))
|
|
||||||
c.Assert(err, check.IsNil)
|
|
||||||
cgSwap, err := strconv.ParseInt(strings.TrimSpace(string(memorySwap)), 10, 64)
|
|
||||||
c.Assert(err, check.IsNil)
|
|
||||||
swap, err := units.RAMInBytes("64m")
|
|
||||||
c.Assert(err, check.IsNil)
|
|
||||||
c.Assert(cgSwap, check.Equals, swap)
|
|
||||||
}
|
|
||||||
|
|
|
@ -37,7 +37,6 @@ docker-create - Create a new container
|
||||||
[**--link**[=*[]*]]
|
[**--link**[=*[]*]]
|
||||||
[**--log-driver**[=*[]*]]
|
[**--log-driver**[=*[]*]]
|
||||||
[**--log-opt**[=*[]*]]
|
[**--log-opt**[=*[]*]]
|
||||||
[**--lxc-conf**[=*[]*]]
|
|
||||||
[**-m**|**--memory**[=*MEMORY*]]
|
[**-m**|**--memory**[=*MEMORY*]]
|
||||||
[**--mac-address**[=*MAC-ADDRESS*]]
|
[**--mac-address**[=*MAC-ADDRESS*]]
|
||||||
[**--memory-reservation**[=*MEMORY-RESERVATION*]]
|
[**--memory-reservation**[=*MEMORY-RESERVATION*]]
|
||||||
|
@ -182,9 +181,6 @@ millions of trillions.
|
||||||
**--log-opt**=[]
|
**--log-opt**=[]
|
||||||
Logging driver specific options.
|
Logging driver specific options.
|
||||||
|
|
||||||
**--lxc-conf**=[]
|
|
||||||
(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
|
|
||||||
|
|
||||||
**-m**, **--memory**=""
|
**-m**, **--memory**=""
|
||||||
Memory limit (format: <number>[<unit>], where unit = b, k, m or g)
|
Memory limit (format: <number>[<unit>], where unit = b, k, m or g)
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,6 @@ To get information on a container use its ID or instance name:
|
||||||
"HostConfig": {
|
"HostConfig": {
|
||||||
"Binds": null,
|
"Binds": null,
|
||||||
"ContainerIDFile": "",
|
"ContainerIDFile": "",
|
||||||
"LxcConf": [],
|
|
||||||
"Memory": 0,
|
"Memory": 0,
|
||||||
"MemorySwap": 0,
|
"MemorySwap": 0,
|
||||||
"CpuShares": 0,
|
"CpuShares": 0,
|
||||||
|
|
|
@ -38,7 +38,6 @@ docker-run - Run a command in a new container
|
||||||
[**--link**[=*[]*]]
|
[**--link**[=*[]*]]
|
||||||
[**--log-driver**[=*[]*]]
|
[**--log-driver**[=*[]*]]
|
||||||
[**--log-opt**[=*[]*]]
|
[**--log-opt**[=*[]*]]
|
||||||
[**--lxc-conf**[=*[]*]]
|
|
||||||
[**-m**|**--memory**[=*MEMORY*]]
|
[**-m**|**--memory**[=*MEMORY*]]
|
||||||
[**--mac-address**[=*MAC-ADDRESS*]]
|
[**--mac-address**[=*MAC-ADDRESS*]]
|
||||||
[**--memory-reservation**[=*MEMORY-RESERVATION*]]
|
[**--memory-reservation**[=*MEMORY-RESERVATION*]]
|
||||||
|
@ -274,9 +273,6 @@ container can access the exposed port via a private networking interface. Docker
|
||||||
will set some environment variables in the client container to help indicate
|
will set some environment variables in the client container to help indicate
|
||||||
which interface and port to use.
|
which interface and port to use.
|
||||||
|
|
||||||
**--lxc-conf**=[]
|
|
||||||
(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
|
|
||||||
|
|
||||||
**--log-driver**="|*json-file*|*syslog*|*journald*|*gelf*|*fluentd*|*awslogs*|*splunk*|*none*"
|
**--log-driver**="|*json-file*|*syslog*|*journald*|*gelf*|*fluentd*|*awslogs*|*splunk*|*none*"
|
||||||
Logging driver for container. Default is defined by daemon `--log-driver` flag.
|
Logging driver for container. Default is defined by daemon `--log-driver` flag.
|
||||||
**Warning**: the `docker logs` command works only for the `json-file` and
|
**Warning**: the `docker logs` command works only for the `json-file` and
|
||||||
|
|
|
@ -298,7 +298,6 @@ the client will even run on alternative platforms such as Mac OS X / Darwin.
|
||||||
Some of Docker's features are activated by using optional command-line flags or
|
Some of Docker's features are activated by using optional command-line flags or
|
||||||
by having support for them in the kernel or userspace. A few examples include:
|
by having support for them in the kernel or userspace. A few examples include:
|
||||||
|
|
||||||
* LXC execution driver (requires version 1.0.7 or later of lxc and the lxc-libs)
|
|
||||||
* AUFS graph driver (requires AUFS patches/support enabled in the kernel, and at
|
* AUFS graph driver (requires AUFS patches/support enabled in the kernel, and at
|
||||||
least the "auplink" utility from aufs-tools)
|
least the "auplink" utility from aufs-tools)
|
||||||
* BTRFS graph driver (requires BTRFS support enabled in the kernel)
|
* BTRFS graph driver (requires BTRFS support enabled in the kernel)
|
||||||
|
|
|
@ -24,7 +24,7 @@ type NetworkMode string
|
||||||
type IsolationLevel string
|
type IsolationLevel string
|
||||||
|
|
||||||
// IsDefault indicates the default isolation level of a container. On Linux this
|
// IsDefault indicates the default isolation level of a container. On Linux this
|
||||||
// is LXC. On Windows, this is a Windows Server Container.
|
// is the native driver. On Windows, this is a Windows Server Container.
|
||||||
func (i IsolationLevel) IsDefault() bool {
|
func (i IsolationLevel) IsDefault() bool {
|
||||||
return strings.ToLower(string(i)) == "default" || string(i) == ""
|
return strings.ToLower(string(i)) == "default" || string(i) == ""
|
||||||
}
|
}
|
||||||
|
@ -164,69 +164,12 @@ type LogConfig struct {
|
||||||
Config map[string]string
|
Config map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// LxcConfig represents the specific LXC configuration of the container.
|
|
||||||
type LxcConfig struct {
|
|
||||||
values []KeyValuePair
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalJSON marshals (or serializes) the LxcConfig into JSON.
|
|
||||||
func (c *LxcConfig) MarshalJSON() ([]byte, error) {
|
|
||||||
if c == nil {
|
|
||||||
return []byte{}, nil
|
|
||||||
}
|
|
||||||
return json.Marshal(c.Slice())
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON unmarshals (or deserializes) the specified byte slices from JSON to
|
|
||||||
// a LxcConfig.
|
|
||||||
func (c *LxcConfig) UnmarshalJSON(b []byte) error {
|
|
||||||
if len(b) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var kv []KeyValuePair
|
|
||||||
if err := json.Unmarshal(b, &kv); err != nil {
|
|
||||||
var h map[string]string
|
|
||||||
if err := json.Unmarshal(b, &h); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for k, v := range h {
|
|
||||||
kv = append(kv, KeyValuePair{k, v})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.values = kv
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len returns the number of specific lxc configuration.
|
|
||||||
func (c *LxcConfig) Len() int {
|
|
||||||
if c == nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return len(c.values)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slice returns the specific lxc configuration into a slice of KeyValuePair.
|
|
||||||
func (c *LxcConfig) Slice() []KeyValuePair {
|
|
||||||
if c == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return c.values
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLxcConfig creates a LxcConfig from the specified slice of KeyValuePair.
|
|
||||||
func NewLxcConfig(values []KeyValuePair) *LxcConfig {
|
|
||||||
return &LxcConfig{values}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HostConfig the non-portable Config structure of a container.
|
// HostConfig the non-portable Config structure of a container.
|
||||||
// Here, "non-portable" means "dependent of the host we are running on".
|
// Here, "non-portable" means "dependent of the host we are running on".
|
||||||
// Portable information *should* appear in Config.
|
// Portable information *should* appear in Config.
|
||||||
type HostConfig struct {
|
type HostConfig struct {
|
||||||
Binds []string // List of volume bindings for this container
|
Binds []string // List of volume bindings for this container
|
||||||
ContainerIDFile string // File (path) where the containerId is written
|
ContainerIDFile string // File (path) where the containerId is written
|
||||||
LxcConf *LxcConfig // Additional lxc configuration
|
|
||||||
Memory int64 // Memory limit (in bytes)
|
Memory int64 // Memory limit (in bytes)
|
||||||
MemoryReservation int64 // Memory soft limit (in bytes)
|
MemoryReservation int64 // Memory soft limit (in bytes)
|
||||||
MemorySwap int64 // Total memory usage (memory + swap); set `-1` to disable swap
|
MemorySwap int64 // Total memory usage (memory + swap); set `-1` to disable swap
|
||||||
|
|
|
@ -162,53 +162,6 @@ func TestRestartPolicy(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLxcConfigMarshalJSON(t *testing.T) {
|
|
||||||
lxcConfigs := map[*LxcConfig]string{
|
|
||||||
nil: "",
|
|
||||||
&LxcConfig{}: "null",
|
|
||||||
&LxcConfig{
|
|
||||||
[]KeyValuePair{{"key1", "value1"}},
|
|
||||||
}: `[{"Key":"key1","Value":"value1"}]`,
|
|
||||||
}
|
|
||||||
|
|
||||||
for lxcconfig, expected := range lxcConfigs {
|
|
||||||
data, err := lxcconfig.MarshalJSON()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if string(data) != expected {
|
|
||||||
t.Fatalf("Expected %v, got %v", expected, string(data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLxcConfigUnmarshalJSON(t *testing.T) {
|
|
||||||
keyvaluePairs := map[string][]KeyValuePair{
|
|
||||||
"": {{"key1", "value1"}},
|
|
||||||
"[]": {},
|
|
||||||
`[{"Key":"key2","Value":"value2"}]`: {{"key2", "value2"}},
|
|
||||||
}
|
|
||||||
for json, expectedParts := range keyvaluePairs {
|
|
||||||
lxcConfig := &LxcConfig{
|
|
||||||
[]KeyValuePair{{"key1", "value1"}},
|
|
||||||
}
|
|
||||||
if err := lxcConfig.UnmarshalJSON([]byte(json)); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
actualParts := lxcConfig.Slice()
|
|
||||||
if len(actualParts) != len(expectedParts) {
|
|
||||||
t.Fatalf("Expected %v keyvaluePairs, got %v (%v)", len(expectedParts), len(actualParts), expectedParts)
|
|
||||||
}
|
|
||||||
for index, part := range actualParts {
|
|
||||||
if part != expectedParts[index] {
|
|
||||||
t.Fatalf("Expected %v, got %v", expectedParts, actualParts)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMergeConfigs(t *testing.T) {
|
func TestMergeConfigs(t *testing.T) {
|
||||||
expectedHostname := "hostname"
|
expectedHostname := "hostname"
|
||||||
expectedContainerIDFile := "containerIdFile"
|
expectedContainerIDFile := "containerIdFile"
|
||||||
|
|
|
@ -62,7 +62,6 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
||||||
flDNSOptions = opts.NewListOpts(nil)
|
flDNSOptions = opts.NewListOpts(nil)
|
||||||
flExtraHosts = opts.NewListOpts(opts.ValidateExtraHost)
|
flExtraHosts = opts.NewListOpts(opts.ValidateExtraHost)
|
||||||
flVolumesFrom = opts.NewListOpts(nil)
|
flVolumesFrom = opts.NewListOpts(nil)
|
||||||
flLxcOpts = opts.NewListOpts(nil)
|
|
||||||
flEnvFile = opts.NewListOpts(nil)
|
flEnvFile = opts.NewListOpts(nil)
|
||||||
flCapAdd = opts.NewListOpts(nil)
|
flCapAdd = opts.NewListOpts(nil)
|
||||||
flCapDrop = opts.NewListOpts(nil)
|
flCapDrop = opts.NewListOpts(nil)
|
||||||
|
@ -121,7 +120,6 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
||||||
cmd.Var(&flDNSOptions, []string{"-dns-opt"}, "Set DNS options")
|
cmd.Var(&flDNSOptions, []string{"-dns-opt"}, "Set DNS options")
|
||||||
cmd.Var(&flExtraHosts, []string{"-add-host"}, "Add a custom host-to-IP mapping (host:ip)")
|
cmd.Var(&flExtraHosts, []string{"-add-host"}, "Add a custom host-to-IP mapping (host:ip)")
|
||||||
cmd.Var(&flVolumesFrom, []string{"#volumes-from", "-volumes-from"}, "Mount volumes from the specified container(s)")
|
cmd.Var(&flVolumesFrom, []string{"#volumes-from", "-volumes-from"}, "Mount volumes from the specified container(s)")
|
||||||
cmd.Var(&flLxcOpts, []string{"#lxc-conf", "-lxc-conf"}, "Add custom lxc options")
|
|
||||||
cmd.Var(&flCapAdd, []string{"-cap-add"}, "Add Linux capabilities")
|
cmd.Var(&flCapAdd, []string{"-cap-add"}, "Add Linux capabilities")
|
||||||
cmd.Var(&flCapDrop, []string{"-cap-drop"}, "Drop Linux capabilities")
|
cmd.Var(&flCapDrop, []string{"-cap-drop"}, "Drop Linux capabilities")
|
||||||
cmd.Var(&flGroupAdd, []string{"-group-add"}, "Add additional groups to join")
|
cmd.Var(&flGroupAdd, []string{"-group-add"}, "Add additional groups to join")
|
||||||
|
@ -223,12 +221,6 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
||||||
entrypoint = stringutils.NewStrSlice(*flEntrypoint)
|
entrypoint = stringutils.NewStrSlice(*flEntrypoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
lc, err := parseKeyValueOpts(flLxcOpts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, cmd, err
|
|
||||||
}
|
|
||||||
lxcConf := NewLxcConfig(lc)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
domainname string
|
domainname string
|
||||||
hostname = *flHostname
|
hostname = *flHostname
|
||||||
|
@ -340,7 +332,6 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
||||||
hostConfig := &HostConfig{
|
hostConfig := &HostConfig{
|
||||||
Binds: binds,
|
Binds: binds,
|
||||||
ContainerIDFile: *flContainerIDFile,
|
ContainerIDFile: *flContainerIDFile,
|
||||||
LxcConf: lxcConf,
|
|
||||||
Memory: flMemory,
|
Memory: flMemory,
|
||||||
MemoryReservation: MemoryReservation,
|
MemoryReservation: MemoryReservation,
|
||||||
MemorySwap: memorySwap,
|
MemorySwap: memorySwap,
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
|
|
||||||
flag "github.com/docker/docker/pkg/mflag"
|
flag "github.com/docker/docker/pkg/mflag"
|
||||||
"github.com/docker/docker/pkg/nat"
|
"github.com/docker/docker/pkg/nat"
|
||||||
"github.com/docker/docker/pkg/parsers"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseRun(args []string) (*Config, *HostConfig, *flag.FlagSet, error) {
|
func parseRun(args []string) (*Config, *HostConfig, *flag.FlagSet, error) {
|
||||||
|
@ -344,35 +343,6 @@ func setupPlatformVolume(u []string, w []string) ([]string, string) {
|
||||||
return a, s
|
return a, s
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseLxcConfOpt(t *testing.T) {
|
|
||||||
opts := []string{"lxc.utsname=docker", "lxc.utsname = docker "}
|
|
||||||
|
|
||||||
for _, o := range opts {
|
|
||||||
k, v, err := parsers.ParseKeyValueOpt(o)
|
|
||||||
if err != nil {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
if k != "lxc.utsname" {
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
if v != "docker" {
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// With parseRun too
|
|
||||||
_, hostconfig, _, err := parseRun([]string{"lxc.utsname=docker", "lxc.utsname = docker ", "img", "cmd"})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
for _, lxcConf := range hostconfig.LxcConf.Slice() {
|
|
||||||
if lxcConf.Key != "lxc.utsname" || lxcConf.Value != "docker" {
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple parse with MacAddress validatation
|
// Simple parse with MacAddress validatation
|
||||||
func TestParseWithMacAddress(t *testing.T) {
|
func TestParseWithMacAddress(t *testing.T) {
|
||||||
invalidMacAddress := "--mac-address=invalidMacAddress"
|
invalidMacAddress := "--mac-address=invalidMacAddress"
|
||||||
|
|
|
@ -61,8 +61,7 @@ func ValidateNetMode(c *Config, hc *HostConfig) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateIsolationLevel performs platform specific validation of the
|
// ValidateIsolationLevel performs platform specific validation of the
|
||||||
// isolation level in the hostconfig structure. Linux only supports "default"
|
// isolation level in the hostconfig structure. Linux only supports "default".
|
||||||
// which is LXC container isolation
|
|
||||||
func ValidateIsolationLevel(hc *HostConfig) error {
|
func ValidateIsolationLevel(hc *HostConfig) error {
|
||||||
// We may not be passed a host config, such as in the case of docker commit
|
// We may not be passed a host config, such as in the case of docker commit
|
||||||
if hc == nil {
|
if hc == nil {
|
||||||
|
|
Loading…
Reference in New Issue