summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorValentin Rothberg <rothberg@redhat.com>2018-12-22 14:59:43 +0100
committerValentin Rothberg <rothberg@redhat.com>2019-01-04 11:42:03 +0100
commit75578aad61c1e9fae021223ece70cb83e3e2bcf2 (patch)
tree2be4469136fd0f7c179352d6a721d2e9f0a61f47
parent9ffd4806163e410d51d0f0cbece45b7405ff9fee (diff)
downloadpodman-75578aad61c1e9fae021223ece70cb83e3e2bcf2.tar.gz
podman-75578aad61c1e9fae021223ece70cb83e3e2bcf2.tar.bz2
podman-75578aad61c1e9fae021223ece70cb83e3e2bcf2.zip
add container-init support
Add support for executing an init binary as PID 1 in a container to forward signals and reap processes. When the `--init` flag is set for podman-create or podman-run, the init binary is bind-mounted to `/dev/init` in the container and "/dev/init --" is prepended to the container's command. The default base path of the container-init binary is `/usr/libexec/podman` while the default binary is catatonit [1]. This default can be changed permanently via the `init_path` field in the `libpod.conf` configuration file (which is recommended for packaging) or temporarily via the `--init-path` flag of podman-create and podman-run. [1] https://github.com/openSUSE/catatonit Fixes: #1670 Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
-rwxr-xr-xAPI.md4
-rw-r--r--Makefile9
-rw-r--r--cmd/podman/common.go9
-rw-r--r--cmd/podman/create.go10
-rw-r--r--cmd/podman/varlink/io.podman.varlink2
-rw-r--r--docs/libpod.conf.5.md3
-rw-r--r--docs/podman-create.1.md8
-rw-r--r--docs/podman-run.1.md8
-rwxr-xr-xhack/install_catatonit.sh15
-rw-r--r--libpod.conf3
-rw-r--r--libpod/runtime.go6
-rw-r--r--pkg/spec/createconfig.go31
-rw-r--r--test/e2e/run_test.go12
13 files changed, 117 insertions, 3 deletions
diff --git a/API.md b/API.md
index 51787496c..3722c2864 100755
--- a/API.md
+++ b/API.md
@@ -1169,6 +1169,10 @@ image [string](https://godoc.org/builtin#string)
image_id [string](https://godoc.org/builtin#string)
+init [bool](https://godoc.org/builtin#bool)
+
+init_path [string](https://godoc.org/builtin#string)
+
builtin_imgvolumes [[]string](#[]string)
id_mappings [IDMappingOptions](#IDMappingOptions)
diff --git a/Makefile b/Makefile
index c423d82f2..32f21227f 100644
--- a/Makefile
+++ b/Makefile
@@ -154,10 +154,10 @@ dbuild: libpodimage
${CONTAINER_RUNTIME} run --name=${LIBPOD_INSTANCE} --privileged -v ${PWD}:/go/src/${PROJECT} --rm ${LIBPOD_IMAGE} make all
test: libpodimage
- ${CONTAINER_RUNTIME} run -e STORAGE_OPTIONS="--storage-driver=vfs" -e TESTFLAGS -e CGROUP_MANAGER=cgroupfs -e TRAVIS -t --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${LIBPOD_IMAGE} make clean all localunit localintegration
+ ${CONTAINER_RUNTIME} run -e STORAGE_OPTIONS="--storage-driver=vfs" -e TESTFLAGS -e CGROUP_MANAGER=cgroupfs -e TRAVIS -t --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${LIBPOD_IMAGE} make clean all localunit install.catatonit localintegration
integration: libpodimage
- ${CONTAINER_RUNTIME} run -e STORAGE_OPTIONS="--storage-driver=vfs" -e TESTFLAGS -e CGROUP_MANAGER=cgroupfs -e TRAVIS -t --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${LIBPOD_IMAGE} make clean all localintegration
+ ${CONTAINER_RUNTIME} run -e STORAGE_OPTIONS="--storage-driver=vfs" -e TESTFLAGS -e CGROUP_MANAGER=cgroupfs -e TRAVIS -t --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${LIBPOD_IMAGE} make clean all install.catatonit localintegration
integration.fedora:
DIST=Fedora sh .papr_prepare.sh
@@ -201,7 +201,10 @@ vagrant-check:
binaries: varlink_generate easyjson_generate podman
-test-binaries: test/bin2img/bin2img test/copyimg/copyimg test/checkseccomp/checkseccomp test/goecho/goecho
+install.catatonit:
+ ./hack/install_catatonit.sh
+
+test-binaries: test/bin2img/bin2img test/copyimg/copyimg test/checkseccomp/checkseccomp test/goecho/goecho install.catatonit
MANPAGES_MD ?= $(wildcard docs/*.md pkg/*/docs/*.md)
MANPAGES ?= $(MANPAGES_MD:%.md=%)
diff --git a/cmd/podman/common.go b/cmd/podman/common.go
index 8404a29b8..0fc9a6acc 100644
--- a/cmd/podman/common.go
+++ b/cmd/podman/common.go
@@ -321,6 +321,15 @@ var createFlags = []cli.Flag{
Value: "bind",
},
cli.BoolFlag{
+ Name: "init",
+ Usage: "Run an init binary inside the container that forwards signals and reaps processes",
+ },
+ cli.StringFlag{
+ Name: "init-path",
+ // Do not use the Value field for setting the default value to determine user input (i.e., non-empty string)
+ Usage: fmt.Sprintf("Path to the container-init binary (default: %q)", libpod.DefaultInitPath),
+ },
+ cli.BoolFlag{
Name: "interactive, i",
Usage: "Keep STDIN open even if not attached",
},
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index dae429047..395a64b3b 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -809,6 +809,16 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
Syslog: c.GlobalBool("syslog"),
}
+ if c.Bool("init") {
+ initPath := c.String("init-path")
+ if initPath == "" {
+ initPath = runtime.GetConfig().InitPath
+ }
+ if err := config.AddContainerInitBinary(initPath); err != nil {
+ return nil, err
+ }
+ }
+
if config.Privileged {
config.LabelOpts = label.DisableSecOpt()
} else {
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index c1b7c703a..4e8b69faf 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -211,6 +211,8 @@ type Create (
hostname: string,
image: string,
image_id: string,
+ init: bool,
+ init_path: string,
builtin_imgvolumes: []string,
id_mappings: IDMappingOptions,
image_volume_type: string,
diff --git a/docs/libpod.conf.5.md b/docs/libpod.conf.5.md
index d63baeb88..c02d247fb 100644
--- a/docs/libpod.conf.5.md
+++ b/docs/libpod.conf.5.md
@@ -24,6 +24,9 @@ libpod to manage containers.
**cgroup_manager**=""
Specify the CGroup Manager to use; valid values are "systemd" and "cgroupfs"
+**init_path**=""
+ Path to the container-init binary, which forwards signals and reaps processes within containers. Note that the container-init binary will only be used when the `--init` for podman-create and podman-run is set.
+
**hooks_dir**=["*path*", ...]
Each `*.json` file in the path configures a hook for Podman containers. For more details on the syntax of the JSON files and the semantics of hook injection, see `oci-hooks(5)`. Podman and libpod currently support both the 1.0.0 and 0.1.0 hook schemas, although the 0.1.0 schema is deprecated.
diff --git a/docs/podman-create.1.md b/docs/podman-create.1.md
index 97d6e77b1..3a75a4b00 100644
--- a/docs/podman-create.1.md
+++ b/docs/podman-create.1.md
@@ -276,6 +276,14 @@ tmpfs: The volume is mounted onto the container as a tmpfs, which allows the use
content that disappears when the container is stopped.
ignore: All volumes are just ignored and no action is taken.
+**--init**
+
+Run an init inside the container that forwards signals and reaps processes.
+
+**--init-path**=""
+
+Path to the container-init binary.
+
**-i**, **--interactive**=*true*|*false*
Keep STDIN open even if not attached. The default is *false*.
diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md
index c0a466a9c..971b8829a 100644
--- a/docs/podman-run.1.md
+++ b/docs/podman-run.1.md
@@ -285,6 +285,14 @@ the container for the volumes.
content that disappears when the container is stopped.
- `ignore`: All volumes are just ignored and no action is taken.
+**--init**
+
+Run an init inside the container that forwards signals and reaps processes.
+
+**--init-path**=""
+
+Path to the container-init binary.
+
**-i**, **--interactive**=*true*|*false*
Keep STDIN open even if not attached. The default is *false*.
diff --git a/hack/install_catatonit.sh b/hack/install_catatonit.sh
new file mode 100755
index 000000000..e5532a200
--- /dev/null
+++ b/hack/install_catatonit.sh
@@ -0,0 +1,15 @@
+#!/bin/bash -e
+BASE_PATH="/usr/libexec/podman"
+CATATONIT_PATH="${BASE_PATH}/catatonit"
+CATATONIT_VERSION="v0.1.3"
+
+if [ -f $CATATONIT_PATH ]; then
+ echo "skipping ... catatonit is already installed"
+else
+ echo "downloading catatonit to $CATATONIT_PATH"
+ curl -o catatonit -L https://github.com/openSUSE/catatonit/releases/download/$CATATONIT_VERSION/catatonit.x86_64
+ chmod +x catatonit
+ install ${SELINUXOPT} -d -m 755 $BASE_PATH
+ install ${SELINUXOPT} -m 755 catatonit $CATATONIT_PATH
+ rm catatonit
+fi
diff --git a/libpod.conf b/libpod.conf
index d7469af68..cfdf83775 100644
--- a/libpod.conf
+++ b/libpod.conf
@@ -35,6 +35,9 @@ conmon_env_vars = [
# CGroup Manager - valid values are "systemd" and "cgroupfs"
cgroup_manager = "systemd"
+# Container init binary
+#init_path = "/usr/libexec/podman/catatonit"
+
# Directory for persistent libpod files (database, etc)
# By default, this will be configured relative to where containers/storage
# stores containers
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 2dfebf565..facbe5d66 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -61,6 +61,9 @@ const (
DefaultInfraImage = "k8s.gcr.io/pause:3.1"
// DefaultInfraCommand to be run in an infra container
DefaultInfraCommand = "/pause"
+
+ // DefaultInitPath is the default path to the container-init binary
+ DefaultInitPath = "/usr/libexec/podman/catatonit"
)
// A RuntimeOption is a functional option which alters the Runtime created by
@@ -122,6 +125,8 @@ type RuntimeConfig struct {
// CGroupManager is the CGroup Manager to use
// Valid values are "cgroupfs" and "systemd"
CgroupManager string `toml:"cgroup_manager"`
+ // InitPath is the path to the container-init binary.
+ InitPath string `toml:"init_path"`
// StaticDir is the path to a persistent directory to store container
// files
StaticDir string `toml:"static_dir"`
@@ -217,6 +222,7 @@ var (
ConmonEnvVars: []string{
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
},
+ InitPath: DefaultInitPath,
CgroupManager: SystemdCgroupsManager,
StaticDir: filepath.Join(storage.DefaultStoreOptions.GraphRoot, "libpod"),
TmpDir: "",
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
index 25f8cd7a1..ffc98e307 100644
--- a/pkg/spec/createconfig.go
+++ b/pkg/spec/createconfig.go
@@ -2,6 +2,7 @@ package createconfig
import (
"encoding/json"
+ "fmt"
"net"
"os"
"strconv"
@@ -145,6 +146,36 @@ func (c *CreateConfig) CreateBlockIO() (*spec.LinuxBlockIO, error) {
return c.createBlockIO()
}
+// AddContainerInitBinary adds the init binary specified by path iff the
+// container will run in a private PID namespace that is not shared with the
+// host or another pre-existing container, where an init-like process is
+// already running.
+//
+// Note that AddContainerInitBinary prepends "/dev/init" "--" to the command
+// to execute the bind-mounted binary as PID 1.
+func (c *CreateConfig) AddContainerInitBinary(path string) error {
+ if path == "" {
+ return fmt.Errorf("please specify a path to the container-init binary")
+ }
+ if !c.PidMode.IsPrivate() {
+ return fmt.Errorf("cannot add init binary as PID 1 (PID namespace isn't private)")
+ }
+ if c.Systemd {
+ return fmt.Errorf("cannot use container-init binary with systemd")
+ }
+ if _, err := os.Stat(path); os.IsNotExist(err) {
+ return errors.Wrap(err, "container-init binary not found on the host")
+ }
+ c.Command = append([]string{"/dev/init", "--"}, c.Command...)
+ c.Mounts = append(c.Mounts, spec.Mount{
+ Destination: "/dev/init",
+ Type: "bind",
+ Source: path,
+ Options: []string{"bind", "ro"},
+ })
+ return nil
+}
+
func processOptions(options []string) []string {
var (
foundrw, foundro bool
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index cf366b197..a0b16a254 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -87,6 +87,18 @@ var _ = Describe("Podman run", func() {
Expect(session.ExitCode()).To(Equal(0))
})
+ It("podman run a container with --init", func() {
+ session := podmanTest.Podman([]string{"run", "--init", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+
+ It("podman run a container with --init and --init-path", func() {
+ session := podmanTest.Podman([]string{"run", "--init", "--init-path", "/usr/libexec/podman/catatonit", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+
It("podman run seccomp test", func() {
jsonFile := filepath.Join(podmanTest.TempDir, "seccomp.json")
in := []byte(`{"defaultAction":"SCMP_ACT_ALLOW","syscalls":[{"name":"getcwd","action":"SCMP_ACT_ERRNO"}]}`)