diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | changelog.txt | 101 | ||||
-rw-r--r-- | cmd/podman/kill.go | 23 | ||||
-rw-r--r-- | cmd/podman/pause.go | 17 | ||||
-rw-r--r-- | cmd/podman/restart.go | 16 | ||||
-rw-r--r-- | cmd/podman/rm.go | 26 | ||||
-rw-r--r-- | cmd/podman/shared/parallel.go | 10 | ||||
-rw-r--r-- | cmd/podman/stop.go | 23 | ||||
-rw-r--r-- | cmd/podman/unpause.go | 18 | ||||
-rw-r--r-- | cmd/podman/utils.go | 17 | ||||
-rw-r--r-- | contrib/cirrus/lib.sh | 3 | ||||
-rw-r--r-- | contrib/spec/podman.spec.in | 2 | ||||
-rw-r--r-- | docs/podman-container.1.md | 1 | ||||
-rw-r--r-- | docs/podman-rm.1.md | 19 | ||||
-rw-r--r-- | docs/podman.1.md | 11 | ||||
-rw-r--r-- | docs/tutorials/podman_tutorial.md | 99 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 58 | ||||
-rw-r--r-- | libpod/info.go | 2 | ||||
-rw-r--r-- | libpod/networking_linux.go | 11 | ||||
-rw-r--r-- | libpod/oci_linux.go | 3 | ||||
-rw-r--r-- | libpod/runtime_ctr.go | 14 | ||||
-rw-r--r-- | pkg/rootless/rootless_linux.go | 3 | ||||
-rw-r--r-- | pkg/util/utils.go | 8 | ||||
-rw-r--r-- | test/e2e/pause_test.go | 19 | ||||
-rw-r--r-- | troubleshooting.md | 26 | ||||
-rw-r--r-- | version/version.go | 2 |
26 files changed, 347 insertions, 187 deletions
@@ -1,6 +1,6 @@ GO ?= go DESTDIR ?= / -EPOCH_TEST_COMMIT ?= 733cfe96819e1dc044e982b5321b3c902d1a47c6 +EPOCH_TEST_COMMIT ?= 921ccac10c47e0865ec5e4ba00ebb69a03d89473 HEAD ?= HEAD CHANGELOG_BASE ?= HEAD~ CHANGELOG_TARGET ?= HEAD diff --git a/changelog.txt b/changelog.txt index ace41f1d9..9aaec0e74 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,104 @@ +- Changelog for v0.11.1 (2018-11-08) + * Update release notes for 0.11.1 + * update seccomp.json + * Touch up --log* options and daemons in man pages + * Fix run --hostname test that started failing post-merge + * move defer'd function declaration ahead of prepare error return + * Don't fail if /etc/passwd or /etc/group does not exists + * Print error status code if we fail to parse it + * Properly set Running state when starting containers + * Fix misspelling + * Retrieve container PID from conmon + * If a container ceases to exist in runc, set exit status + * EXPERIMENTAL: Do not call out to runc for sync + * Actually save changes from post-stop sync + * rootless: mount /sys/fs/cgroup/systemd from the host + * rootless: don't bind mount /sys/fs/cgroup/systemd in systemd mode + * Add hostname to /etc/hosts + * Temporarily fix the Python tests to fix some PRs + * Remove conmon cgroup before pod cgroup for cgroupfs + * Fix cleanup for "Pause a bunch of running containers" + * --interactive shall keep STDIN attached even when not explicitly called out + * Do never override podman with docker + * Make kill, pause, and unpause parallel. + * Fix long image name handling + * Make restart parallel and add --all + * Add ChangeAction to parse sub-options from --change + * replace quay.io/baude to quay.io/libpod + * Change humanize to use MB vs MiB. + * allow ppc64le to pass libpod integration tests + * Cirrus-CI: Add option to run system-tests + * Cirrus: Skip rebuilding images unless instructed + * Cirrus: Disable image build job abort on push + * Cirrus: Add a readme + * Ubuntu VM image build: try update twice + * Cirrus: Enable updating F28 image + * rootless: do not add an additional /run to runroot + * rootless: avoid hang on failed slirp4netns + * Fix setting of version information + * runtime: do not allow runroot longer than 50 characters + * attach: fix attach when cuid is too long + * truncate command output in ps by default + * Update the runc commit used for testing + * make various changes to ps output + * Sync default config with libpod.conf + * Use two spaces to pad PS fields + * unmount: fix error logic + * get user and group information using securejoin and runc's user library + * CONTRIBUTING.md: add section about describing changes + * Change to exported name in ParseDevice + * Vendor in latest containers/storage + * fix bug in rm -fa parallel deletes + * Ensure test container in running state + * Add tests for selinux labels + * Add --max-workers and heuristics for parallel operations + * Increase security and performance when looking up groups + * run prepare in parallel + * downgrade runc due a rootless bug + * runlabel: run any command + * Eat our own dogfood + * vendor: update containers/storage + * Add support for /usr/local installation + * create: fix writing cidfile when using rootless + * Explain the device format in man pages + * read conmon output and convert to json in two steps + * Cirrus: Use images w/ buildah fix + * Add --all and --latest to checkpoint/restore + * Use the newly added getAllOrLatestContainers() function + * Use the new checkAllAndLatest() function + * Also factor out getAllOrLatestContainers() function + * Add checkAllAndLatest() function + * Downgrade code to support python3.4 + * Allow containers/storage to handle on SELinux labeling + * Use more reliable check for rootless for firewall init + * Vendor in latest containers/storage opencontainers/selinux + * Make podman ps fast + * Support auth file environment variable in podman build + * fix environment variable parsing + * tests: use existing CRIU version check + * Use the CRIU version check in checkpoint/restore + * Add helper function to read out CRIU version + * vendor in go-criu and dependencies + * oci: cleanup process status + * Handle http/https in registry given to login/out + * re-enable f29 testing + * correct stats err with non-running containers + * Use restoreArtifacts to save time in integration tests + * Make rm faster + * Fix man page to show info on storage + * Move rootless directory handling to the libpod/pkg/util directory + * Fix podman port -l + * Fix trivial missing markup in manpage + * Cirrus: Install CRIU in test images + * Cirrus: Use different CNI_COMMIT for Fedora + * Fix Cirrus/Packer VM image building + * Revert "Cirrus: Enable debugging delay on non-zero exit" + * Cirrus: IRC message when cirrus testing successful + * cirrus: Add simple IRC messenger + * fix NOTIFY_SOCKET in e2e testfix NOTIFY_SOCKET in e2e tests + * Bump gitvalidation epoch + * Bump to v0.10.2-dev + - Changelog for v0.10.1.3 (2018-10-17) * Update release notes for 0.10.1.3 * Vendor in new new buildah/ci diff --git a/cmd/podman/kill.go b/cmd/podman/kill.go index 27882aeee..cfe4b4218 100644 --- a/cmd/podman/kill.go +++ b/cmd/podman/kill.go @@ -43,7 +43,6 @@ var ( // killCmd kills one or more containers with a signal func killCmd(c *cli.Context) error { var ( - lastError error killFuncs []shared.ParallelWorkerInput killSignal uint = uint(syscall.SIGTERM) ) @@ -75,8 +74,12 @@ func killCmd(c *cli.Context) error { containers, err := getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running") if err != nil { - return err + if len(containers) == 0 { + return err + } + fmt.Println(err.Error()) } + for _, ctr := range containers { con := ctr f := func() error { @@ -95,18 +98,6 @@ func killCmd(c *cli.Context) error { } logrus.Debugf("Setting maximum workers to %d", maxWorkers) - killErrors := shared.ParallelExecuteWorkerPool(maxWorkers, killFuncs) - - for cid, result := range killErrors { - if result != nil { - if len(killErrors) > 1 { - fmt.Println(result.Error()) - } - lastError = result - continue - } - fmt.Println(cid) - } - - return lastError + killErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, killFuncs) + return printParallelOutput(killErrors, errCount) } diff --git a/cmd/podman/pause.go b/cmd/podman/pause.go index 1e1585216..fcb2f3cb8 100644 --- a/cmd/podman/pause.go +++ b/cmd/podman/pause.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "os" "github.com/containers/libpod/cmd/podman/libpodruntime" @@ -37,7 +36,6 @@ var ( func pauseCmd(c *cli.Context) error { var ( - lastError error pauseContainers []*libpod.Container pauseFuncs []shared.ParallelWorkerInput ) @@ -90,17 +88,6 @@ func pauseCmd(c *cli.Context) error { } logrus.Debugf("Setting maximum workers to %d", maxWorkers) - pauseErrors := shared.ParallelExecuteWorkerPool(maxWorkers, pauseFuncs) - - for cid, result := range pauseErrors { - if result != nil { - if len(pauseErrors) > 1 { - fmt.Println(result.Error()) - } - lastError = result - continue - } - fmt.Println(cid) - } - return lastError + pauseErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, pauseFuncs) + return printParallelOutput(pauseErrors, errCount) } diff --git a/cmd/podman/restart.go b/cmd/podman/restart.go index 2e264db79..630493ef4 100644 --- a/cmd/podman/restart.go +++ b/cmd/podman/restart.go @@ -1,8 +1,6 @@ package main import ( - "fmt" - "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod" @@ -46,7 +44,6 @@ func restartCmd(c *cli.Context) error { var ( restartFuncs []shared.ParallelWorkerInput containers []*libpod.Container - lastError error restartContainers []*libpod.Container ) @@ -124,15 +121,6 @@ func restartCmd(c *cli.Context) error { logrus.Debugf("Setting maximum workers to %d", maxWorkers) - restartErrors := shared.ParallelExecuteWorkerPool(maxWorkers, restartFuncs) - - for cid, result := range restartErrors { - if result != nil { - fmt.Println(result.Error()) - lastError = result - continue - } - fmt.Println(cid) - } - return lastError + restartErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, restartFuncs) + return printParallelOutput(restartErrors, errCount) } diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go index 0fb5345ee..7c0569b78 100644 --- a/cmd/podman/rm.go +++ b/cmd/podman/rm.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/cmd/podman/shared" - "github.com/containers/libpod/libpod" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -46,9 +45,7 @@ Running containers will not be removed without the -f option. // saveCmd saves the image to either docker-archive or oci func rmCmd(c *cli.Context) error { var ( - delContainers []*libpod.Container - lastError error - deleteFuncs []shared.ParallelWorkerInput + deleteFuncs []shared.ParallelWorkerInput ) ctx := getContext() @@ -65,7 +62,13 @@ func rmCmd(c *cli.Context) error { return err } - delContainers, lastError = getAllOrLatestContainers(c, runtime, -1, "all") + delContainers, err := getAllOrLatestContainers(c, runtime, -1, "all") + if err != nil { + if len(delContainers) == 0 { + return err + } + fmt.Println(err.Error()) + } for _, container := range delContainers { con := container @@ -84,14 +87,7 @@ func rmCmd(c *cli.Context) error { } logrus.Debugf("Setting maximum workers to %d", maxWorkers) - deleteErrors := shared.ParallelExecuteWorkerPool(maxWorkers, deleteFuncs) - for cid, result := range deleteErrors { - if result != nil { - fmt.Println(result.Error()) - lastError = result - continue - } - fmt.Println(cid) - } - return lastError + // Run the parallel funcs + deleteErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, deleteFuncs) + return printParallelOutput(deleteErrors, errCount) } diff --git a/cmd/podman/shared/parallel.go b/cmd/podman/shared/parallel.go index 633781a45..e6ce50f95 100644 --- a/cmd/podman/shared/parallel.go +++ b/cmd/podman/shared/parallel.go @@ -30,9 +30,10 @@ func ParallelWorker(wg *sync.WaitGroup, jobs <-chan ParallelWorkerInput, results // ParallelExecuteWorkerPool takes container jobs and performs them in parallel. The worker // int determines how many workers/threads should be premade. -func ParallelExecuteWorkerPool(workers int, functions []ParallelWorkerInput) map[string]error { +func ParallelExecuteWorkerPool(workers int, functions []ParallelWorkerInput) (map[string]error, int) { var ( - wg sync.WaitGroup + wg sync.WaitGroup + errorCount int ) resultChan := make(chan containerError, len(functions)) @@ -62,9 +63,12 @@ func ParallelExecuteWorkerPool(workers int, functions []ParallelWorkerInput) map close(resultChan) for ctrError := range resultChan { results[ctrError.ContainerID] = ctrError.Err + if ctrError.Err != nil { + errorCount += 1 + } } - return results + return results, errorCount } // Parallelize provides the maximum number of parallel workers (int) as calculated by a basic diff --git a/cmd/podman/stop.go b/cmd/podman/stop.go index cb36fd5cd..04022839a 100644 --- a/cmd/podman/stop.go +++ b/cmd/podman/stop.go @@ -59,7 +59,13 @@ func stopCmd(c *cli.Context) error { } defer runtime.Shutdown(false) - containers, lastError := getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running") + containers, err := getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running") + if err != nil { + if len(containers) == 0 { + return err + } + fmt.Println(err.Error()) + } var stopFuncs []shared.ParallelWorkerInput for _, ctr := range containers { @@ -85,17 +91,6 @@ func stopCmd(c *cli.Context) error { } logrus.Debugf("Setting maximum workers to %d", maxWorkers) - stopErrors := shared.ParallelExecuteWorkerPool(maxWorkers, stopFuncs) - - for cid, result := range stopErrors { - if result != nil && result != libpod.ErrCtrStopped { - if len(stopErrors) > 1 { - fmt.Println(result.Error()) - } - lastError = result - continue - } - fmt.Println(cid) - } - return lastError + stopErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, stopFuncs) + return printParallelOutput(stopErrors, errCount) } diff --git a/cmd/podman/unpause.go b/cmd/podman/unpause.go index 648fc9d3d..d77e056f8 100644 --- a/cmd/podman/unpause.go +++ b/cmd/podman/unpause.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "os" "github.com/containers/libpod/cmd/podman/libpodruntime" @@ -37,7 +36,6 @@ var ( func unpauseCmd(c *cli.Context) error { var ( - lastError error unpauseContainers []*libpod.Container unpauseFuncs []shared.ParallelWorkerInput ) @@ -90,18 +88,6 @@ func unpauseCmd(c *cli.Context) error { } logrus.Debugf("Setting maximum workers to %d", maxWorkers) - unpauseErrors := shared.ParallelExecuteWorkerPool(maxWorkers, unpauseFuncs) - - for cid, result := range unpauseErrors { - if result != nil && result != libpod.ErrCtrStopped { - if len(unpauseErrors) > 1 { - fmt.Println(result.Error()) - } - lastError = result - continue - } - fmt.Println(cid) - } - - return lastError + unpauseErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, unpauseFuncs) + return printParallelOutput(unpauseErrors, errCount) } diff --git a/cmd/podman/utils.go b/cmd/podman/utils.go index afeccb668..5735156c2 100644 --- a/cmd/podman/utils.go +++ b/cmd/podman/utils.go @@ -207,3 +207,20 @@ func getPodsFromContext(c *cli.Context, r *libpod.Runtime) ([]*libpod.Pod, error } return pods, lastError } + +//printParallelOutput takes the map of parallel worker results and outputs them +// to stdout +func printParallelOutput(m map[string]error, errCount int) error { + var lastError error + for cid, result := range m { + if result != nil { + if errCount > 1 { + fmt.Println(result.Error()) + } + lastError = result + continue + } + fmt.Println(cid) + } + return lastError +} diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh index 2fa91258b..4a3efb8ff 100644 --- a/contrib/cirrus/lib.sh +++ b/contrib/cirrus/lib.sh @@ -106,7 +106,10 @@ ircmsg() { SCRIPT="$GOSRC/$SCRIPT_BASE/podbot.py" NICK="podbot_$CIRRUS_TASK_ID" NICK="${NICK:0:15}" # Any longer will break things + set +e $SCRIPT $NICK $1 + echo "Ignoring exit($?)" + set -e } # Run sudo in directory with GOPATH set diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in index c2d8fc59d..f6ebfa148 100644 --- a/contrib/spec/podman.spec.in +++ b/contrib/spec/podman.spec.in @@ -39,7 +39,7 @@ %global shortcommit_conmon %(c=%{commit_conmon}; echo ${c:0:7}) Name: podman -Version: 0.10.2 +Version: 0.11.2 Release: #COMMITDATE#.git%{shortcommit0}%{?dist} Summary: Manage Pods, Containers and Container Images License: ASL 2.0 diff --git a/docs/podman-container.1.md b/docs/podman-container.1.md index eac3343d5..67d42bfef 100644 --- a/docs/podman-container.1.md +++ b/docs/podman-container.1.md @@ -38,7 +38,6 @@ The container command allows you to manage containers | stop | [podman-stop(1)](podman-stop.1.md) | Stop one or more running containers. | | top | [podman-top(1)](podman-top.1.md) | Display the running processes of a container. | | umount | [podman-umount(1)](podman-umount.1.md) | Unmount a working container's root filesystem. | -| unmount | [podman-umount(1)](podman-umount.1.md) | Unmount a working container's root filesystem. | | unpause | [podman-unpause(1)](podman-unpause.1.md) | Unpause one or more containers. | | wait | [podman-wait(1)](podman-wait.1.md) | Wait on one or more containers to stop and print their exit codes. | diff --git a/docs/podman-rm.1.md b/docs/podman-rm.1.md index 7474a0d1f..56664a8c1 100644 --- a/docs/podman-rm.1.md +++ b/docs/podman-rm.1.md @@ -13,7 +13,7 @@ podman\-rm - Remove one or more containers **--force, f** -Force the removal of a running container +Force the removal of a running and paused containers **--all, a** @@ -29,16 +29,29 @@ to run containers such as CRI-O, the last started container could be from either Remove the volumes associated with the container. (Not yet implemented) ## EXAMPLE - +Remove a container by its name *mywebserver* +``` podman rm mywebserver - +``` +Remove several containers by name and container id. +``` podman rm mywebserver myflaskserver 860a4b23 +``` +Forcibly remove a container by container ID. +``` podman rm -f 860a4b23 +``` +Remove all containers regardless of its run state. +``` podman rm -f -a +``` +Forcibly remove the latest container created. +``` podman rm -f --latest +``` ## SEE ALSO podman(1), podman-rmi(1) diff --git a/docs/podman.1.md b/docs/podman.1.md index 085af97ff..b7433d850 100644 --- a/docs/podman.1.md +++ b/docs/podman.1.md @@ -56,7 +56,7 @@ Path to the OCI compatible binary used to run containers **--storage-driver, -s**=**value** -Storage driver. The default storage driver for UID 0 is configured in /etc/containers/storage.conf (`$HOME/.config/containers/storage.conf` in rootless mode), and is *vfs* for other users. The `STORAGE_DRIVER` environment variable overrides the default. The --storage-driver specified driver overrides all. +Storage driver. The default storage driver for UID 0 is configured in /etc/containers/storage.conf (`$HOME/.config/containers/storage.conf` in rootless mode), and is *vfs* for non-root users when *fuse-overlayfs* is not available. The `STORAGE_DRIVER` environment variable overrides the default. The --storage-driver specified driver overrides all. Overriding this option will cause the *storage-opt* settings in /etc/containers/storage.conf to be ignored. The user must specify additional options via the `--storage-opt` flag. @@ -192,7 +192,7 @@ the exit codes follow the `chroot` standard, see below: When Podman runs in rootless mode, the file `$HOME/.config/containers/storage.conf` is also loaded. ## Rootless mode -Podman can also be used as non-root user. When podman runs in rootless mode, an user namespace is automatically created. +Podman can also be used as non-root user. When podman runs in rootless mode, a user namespace is automatically created for the user, defined in /etc/subuid and /etc/subgid. Containers created by a non-root user are not visible to other users and are not seen or managed by podman running as root. @@ -209,13 +209,14 @@ Or just add the content manually. $ echo USERNAME:10000:65536 >> /etc/subuid $ echo USERNAME:10000:65536 >> /etc/subgid +See the `subuid(5)` and `subgid(5)` man pages for more information. + Images are pulled under `XDG_DATA_HOME` when specified, otherwise in the home directory of the user under `.local/share/containers/storage`. -Currently it is not possible to create a network device, so rootless containers need to run in the host network namespace. If a rootless container creates a network namespace, -then only the loopback device will be available. +Currently the slirp4netns package is required to be installed to create a network device, otherwise rootless containers need to run in the network namespace of the host. ## SEE ALSO -`containers-mounts.conf(5)`, `containers-registries.conf(5)`, `containers-storage.conf(5)`, `crio(8)`, `libpod.conf(5)`, `oci-hooks(5)`, `policy.json(5)` +`containers-mounts.conf(5)`, `containers-registries.conf(5)`, `containers-storage.conf(5)`, `crio(8)`, `libpod.conf(5)`, `oci-hooks(5)`, `policy.json(5)`, `subuid(5)`, `subgid(5)`, `slirp4netns(1)` ## HISTORY Dec 2016, Originally compiled by Dan Walsh <dwalsh@redhat.com> diff --git a/docs/tutorials/podman_tutorial.md b/docs/tutorials/podman_tutorial.md index 152d65a59..5a8f997b8 100644 --- a/docs/tutorials/podman_tutorial.md +++ b/docs/tutorials/podman_tutorial.md @@ -5,10 +5,13 @@ Podman is a utility provided as part of the libpod library. It can be used to c containers. The following tutorial will teach you how to set up Podman and perform some basic commands with Podman. +**NOTE**: the code samples are intended to be run as a non-root user, and use `sudo` where +root escalation is required. + ## Install Podman on Fedora from RPM Repositories Fedora 27 and later provide Podman via the package manager. ```console -$ sudo dnf install -y podman +sudo dnf install -y podman ``` ## Install Podman on Fedora from Source @@ -18,10 +21,10 @@ acquire the source, and build it. ### Installing build and runtime dependencies ```console -$ sudo dnf install -y git runc libassuan-devel golang golang-github-cpuguy83-go-md2man glibc-static \ - gpgme-devel glib2-devel device-mapper-devel libseccomp-devel \ - atomic-registries iptables skopeo-containers containernetworking-cni \ - conmon +sudo dnf install -y git runc libassuan-devel golang golang-github-cpuguy83-go-md2man glibc-static \ + gpgme-devel glib2-devel device-mapper-devel libseccomp-devel \ + atomic-registries iptables skopeo-containers containernetworking-cni \ + conmon ``` ### Building and installing podman @@ -29,12 +32,12 @@ First, configure a `GOPATH` (if you are using go1.8 or later, this defaults to ` and make libpod. ```console -$ export GOPATH=~/go -$ mkdir -p $GOPATH -$ git clone https://github.com/containers/libpod/ $GOPATH/src/github.com/containers/libpod -$ cd $GOPATH/src/github.com/containers/libpod -$ make -$ sudo make install PREFIX=/usr +export GOPATH=~/go +mkdir -p $GOPATH +git clone https://github.com/containers/libpod/ $GOPATH/src/github.com/containers/libpod +cd $GOPATH/src/github.com/containers/libpod +make +sudo make install PREFIX=/usr ``` You now have a working podman environment. Jump to [Familiarizing yourself with Podman](#familiarizing-yourself-with-podman) @@ -50,8 +53,8 @@ tutorial. For this tutorial, the Ubuntu **artful-server-cloudimg** image was use #### Installing base packages ```console -$ sudo apt-get update -$ sudo apt-get install libdevmapper-dev libglib2.0-dev libgpgme11-dev golang libseccomp-dev \ +sudo apt-get update +sudo apt-get install libdevmapper-dev libglib2.0-dev libgpgme11-dev golang libseccomp-dev \ go-md2man libprotobuf-dev libprotobuf-c0-dev libseccomp-dev python3-setuptools ``` #### Building and installing conmon @@ -59,42 +62,42 @@ First, configure a `GOPATH` (if you are using go1.8 or later, this defaults to ` and make libpod. ```console -$ export GOPATH=~/go -$ mkdir -p $GOPATH -$ git clone https://github.com/kubernetes-sigs/cri-o $GOPATH/src/github.com/kubernetes-sigs/cri-o -$ cd $GOPATH/src/github.com/kubernetes-sigs/cri-o -$ mkdir bin -$ make bin/conmon -$ sudo install -D -m 755 bin/conmon /usr/libexec/podman/conmon +export GOPATH=~/go +mkdir -p $GOPATH +git clone https://github.com/kubernetes-sigs/cri-o $GOPATH/src/github.com/kubernetes-sigs/cri-o +cd $GOPATH/src/github.com/kubernetes-sigs/cri-o +mkdir bin +make bin/conmon +sudo install -D -m 755 bin/conmon /usr/libexec/podman/conmon ``` #### Adding required configuration files ```console -$ sudo mkdir -p /etc/containers -$ sudo curl https://raw.githubusercontent.com/projectatomic/registries/master/registries.fedora -o /etc/containers/registries.conf -$ sudo curl https://raw.githubusercontent.com/containers/skopeo/master/default-policy.json -o /etc/containers/policy.json +sudo mkdir -p /etc/containers +sudo curl https://raw.githubusercontent.com/projectatomic/registries/master/registries.fedora -o /etc/containers/registries.conf +sudo curl https://raw.githubusercontent.com/containers/skopeo/master/default-policy.json -o /etc/containers/policy.json ``` #### Installing CNI plugins ```console -$ git clone https://github.com/containernetworking/plugins.git $GOPATH/src/github.com/containernetworking/plugins -$ cd $GOPATH/src/github.com/containernetworking/plugins -$ ./build.sh -$ sudo mkdir -p /usr/libexec/cni -$ sudo cp bin/* /usr/libexec/cni +git clone https://github.com/containernetworking/plugins.git $GOPATH/src/github.com/containernetworking/plugins +cd $GOPATH/src/github.com/containernetworking/plugins +./build_linux.sh +sudo mkdir -p /usr/libexec/cni +sudo cp bin/* /usr/libexec/cni ``` #### Installing runc ```console -$ git clone https://github.com/opencontainers/runc.git $GOPATH/src/github.com/opencontainers/runc -$ cd $GOPATH/src/github.com/opencontainers/runc -$ make BUILDTAGS="seccomp" -$ sudo cp runc /usr/bin/runc +git clone https://github.com/opencontainers/runc.git $GOPATH/src/github.com/opencontainers/runc +cd $GOPATH/src/github.com/opencontainers/runc +make BUILDTAGS="seccomp" +sudo cp runc /usr/bin/runc ``` ### Building and installing Podman ```console -$ git clone https://github.com/containers/libpod/ $GOPATH/src/github.com/containers/libpod -$ cd $GOPATH/src/github.com/containers/libpod -$ make -$ sudo make install PREFIX=/usr +git clone https://github.com/containers/libpod/ $GOPATH/src/github.com/containers/libpod +cd $GOPATH/src/github.com/containers/libpod +make +sudo make install PREFIX=/usr ``` ## Familiarizing yourself with Podman @@ -103,10 +106,10 @@ $ sudo make install PREFIX=/usr This sample container will run a very basic httpd server that serves only its index page. ```console -$ sudo podman run -dt -e HTTPD_VAR_RUN=/var/run/httpd -e HTTPD_MAIN_CONF_D_PATH=/etc/httpd/conf.d \ - -e HTTPD_MAIN_CONF_PATH=/etc/httpd/conf \ - -e HTTPD_CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/httpd/ \ - registry.fedoraproject.org/f27/httpd /usr/bin/run-httpd +sudo podman run -dt -e HTTPD_VAR_RUN=/var/run/httpd -e HTTPD_MAIN_CONF_D_PATH=/etc/httpd/conf.d \ + -e HTTPD_MAIN_CONF_PATH=/etc/httpd/conf \ + -e HTTPD_CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/httpd/ \ + registry.fedoraproject.org/f27/httpd /usr/bin/run-httpd ``` Because the container is being run in detached mode, represented by the *-d* in the podman run command, podman will print the container ID after it has run. @@ -114,7 +117,7 @@ will print the container ID after it has run. ### Listing running containers The Podman *ps* command is used to list creating and running containers. ```console -$ sudo podman ps +sudo podman ps ``` Note: If you add *-a* to the *ps* command, Podman will show all containers. @@ -134,7 +137,7 @@ Now that we have the IP address of the container, we can test the network commun operating system and the container using curl. The following command should display the index page of our containerized httpd server. ```console -# curl http://<IP_address>:8080 +curl http://<IP_address>:8080 ``` ### Viewing the container's logs @@ -163,7 +166,7 @@ With this a container can later be restored and continue running at exactly the checkpoint. This capability requires CRIU 3.11 or later installed on the system. To checkpoint the container use: ```console -$ sudo podman container checkpoint <container_id> +sudo podman container checkpoint <container_id> ``` ### Restoring the container @@ -171,29 +174,29 @@ Restoring a container is only possible for a previously checkpointed container. continue to run at exactly the same point in time it was checkpointed. To restore the container use: ```console -$ sudo podman container restore <container_id> +sudo podman container restore <container_id> ``` After being restored, the container will answer requests again as it did before checkpointing. ```console -# curl http://<IP_address>:8080 +curl http://<IP_address>:8080 ``` ### Stopping the container To stop the httpd container: ```console -$ sudo podman stop --latest +sudo podman stop --latest ``` You can also check the status of one or more containers using the *ps* subcommand. In this case, we should use the *-a* argument to list all containers. ```console -$ sudo podman ps -a +sudo podman ps -a ``` ### Removing the container To remove the httpd container: ```console -$ sudo podman rm --latest +sudo podman rm --latest ``` You can verify the deletion of the container by running *podman ps -a*. diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 163cd75e7..66c7e8a04 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -57,7 +57,7 @@ func (c *Container) prepare() (err error) { networkStatus []*cnitypes.Result createNetNSErr, mountStorageErr error mountPoint string - saveNetworkStatus bool + tmpStateLock sync.Mutex ) wg.Add(2) @@ -66,17 +66,55 @@ func (c *Container) prepare() (err error) { defer wg.Done() // Set up network namespace if not already set up if c.config.CreateNetNS && c.state.NetNS == nil && !c.config.PostConfigureNetNS { - saveNetworkStatus = true netNS, networkStatus, createNetNSErr = c.runtime.createNetNS(c) + + tmpStateLock.Lock() + defer tmpStateLock.Unlock() + + // Assign NetNS attributes to container + if createNetNSErr == nil { + c.state.NetNS = netNS + c.state.NetworkStatus = networkStatus + } } }() // Mount storage if not mounted go func() { defer wg.Done() mountPoint, mountStorageErr = c.mountStorage() + + if mountStorageErr != nil { + return + } + + tmpStateLock.Lock() + defer tmpStateLock.Unlock() + + // Finish up mountStorage + c.state.Mounted = true + c.state.Mountpoint = mountPoint + if c.state.UserNSRoot == "" { + c.state.RealMountpoint = c.state.Mountpoint + } else { + c.state.RealMountpoint = filepath.Join(c.state.UserNSRoot, "mountpoint") + } + + logrus.Debugf("Created root filesystem for container %s at %s", c.ID(), c.state.Mountpoint) + }() + + defer func() { + if err != nil { + if err2 := c.cleanupNetwork(); err2 != nil { + logrus.Errorf("Error cleaning up container %s network: %v", c.ID(), err2) + } + if err2 := c.cleanupStorage(); err2 != nil { + logrus.Errorf("Error cleaning up container %s storage: %v", c.ID(), err2) + } + } }() wg.Wait() + if createNetNSErr != nil { if mountStorageErr != nil { logrus.Error(createNetNSErr) @@ -88,22 +126,6 @@ func (c *Container) prepare() (err error) { return mountStorageErr } - // Assign NetNS attributes to container - if saveNetworkStatus { - c.state.NetNS = netNS - c.state.NetworkStatus = networkStatus - } - - // Finish up mountStorage - c.state.Mounted = true - c.state.Mountpoint = mountPoint - if c.state.UserNSRoot == "" { - c.state.RealMountpoint = c.state.Mountpoint - } else { - c.state.RealMountpoint = filepath.Join(c.state.UserNSRoot, "mountpoint") - } - - logrus.Debugf("Created root filesystem for container %s at %s", c.ID(), c.state.Mountpoint) // Save the container return c.save() } diff --git a/libpod/info.go b/libpod/info.go index 4cbf3f734..5d8d160c8 100644 --- a/libpod/info.go +++ b/libpod/info.go @@ -12,6 +12,7 @@ import ( "strings" "time" + "github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/utils" "github.com/containers/storage/pkg/system" "github.com/pkg/errors" @@ -30,6 +31,7 @@ func (r *Runtime) hostInfo() (map[string]interface{}, error) { info["os"] = runtime.GOOS info["arch"] = runtime.GOARCH info["cpus"] = runtime.NumCPU() + info["rootless"] = rootless.IsRootless() mi, err := system.ReadMemInfo() if err != nil { return nil, errors.Wrapf(err, "error reading memory info") diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index 863a764e2..43d0a61a4 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -64,20 +64,20 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re } }() - networkStatus := make([]*cnitypes.Result, 1) + networkStatus := make([]*cnitypes.Result, 0) for idx, r := range results { logrus.Debugf("[%d] CNI result: %v", idx, r.String()) resultCurrent, err := cnitypes.GetResult(r) if err != nil { return nil, errors.Wrapf(err, "error parsing CNI plugin result %q: %v", r.String(), err) } - networkStatus = append(ctr.state.NetworkStatus, resultCurrent) + networkStatus = append(networkStatus, resultCurrent) } // Add firewall rules to ensure the container has network access. // Will not be necessary once CNI firewall plugin merges upstream. // https://github.com/containernetworking/plugins/pull/75 - for _, netStatus := range ctr.state.NetworkStatus { + for _, netStatus := range networkStatus { firewallConf := &firewall.FirewallNetConf{ PrevResult: netStatus, } @@ -90,13 +90,16 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re } // Create and configure a new network namespace for a container -func (r *Runtime) createNetNS(ctr *Container) (ns.NetNS, []*cnitypes.Result, error) { +func (r *Runtime) createNetNS(ctr *Container) (n ns.NetNS, q []*cnitypes.Result, err error) { ctrNS, err := netns.NewNS() if err != nil { return nil, nil, errors.Wrapf(err, "error creating network namespace for container %s", ctr.ID()) } defer func() { if err != nil { + if err2 := netns.UnmountNS(ctrNS); err2 != nil { + logrus.Errorf("Error unmounting partially created network namespace for container %s: %v", ctr.ID(), err2) + } if err2 := ctrNS.Close(); err2 != nil { logrus.Errorf("Error closing partially created network namespace for container %s: %v", ctr.ID(), err2) } diff --git a/libpod/oci_linux.go b/libpod/oci_linux.go index 0447670b3..e6b7cbe4f 100644 --- a/libpod/oci_linux.go +++ b/libpod/oci_linux.go @@ -74,7 +74,8 @@ func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string, restor defer wg.Done() runtime.LockOSThread() - fd, err := os.Open(fmt.Sprintf("/proc/%d/task/%d/ns/mnt", os.Getpid(), unix.Gettid())) + var fd *os.File + fd, err = os.Open(fmt.Sprintf("/proc/%d/task/%d/ns/mnt", os.Getpid(), unix.Gettid())) if err != nil { return } diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index 09dc7c48b..09d0ec042 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -246,7 +246,19 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool) } if c.state.State == ContainerStatePaused { - return errors.Wrapf(ErrCtrStateInvalid, "container %s is paused, cannot remove until unpaused", c.ID()) + if !force { + return errors.Wrapf(ErrCtrStateInvalid, "container %s is paused, cannot remove until unpaused", c.ID()) + } + if err := c.runtime.ociRuntime.killContainer(c, 9); err != nil { + return err + } + if err := c.unpause(); err != nil { + return err + } + // Need to update container state to make sure we know it's stopped + if err := c.waitForExitFileAndSync(); err != nil { + return err + } } // Check that the container's in a good state to be removed diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go index 5c45f2694..ff8c8fe34 100644 --- a/pkg/rootless/rootless_linux.go +++ b/pkg/rootless/rootless_linux.go @@ -187,6 +187,9 @@ func BecomeRootInUserNS() (bool, int, error) { if username == "" { user, err := user.LookupId(fmt.Sprintf("%d", os.Getuid())) if err != nil && os.Getenv("PODMAN_ALLOW_SINGLE_ID_MAPPING_IN_USERNS") == "" { + if os.IsNotExist(err) { + return false, 0, errors.Wrapf(err, "/etc/subuid or /etc/subgid does not exist, see subuid/subgid man pages for information on these files") + } return false, 0, errors.Wrapf(err, "could not find user by UID nor USER env was set") } if err == nil { diff --git a/pkg/util/utils.go b/pkg/util/utils.go index 69f49e72a..3b43489b2 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -3,6 +3,7 @@ package util import ( "fmt" "os" + "os/exec" "path/filepath" "strconv" "strings" @@ -273,7 +274,12 @@ func GetRootlessStorageOpts() (storage.StoreOptions, error) { dataDir = filepath.Join(resolvedHome, ".local", "share") } opts.GraphRoot = filepath.Join(dataDir, "containers", "storage") - opts.GraphDriverName = "vfs" + if path, err := exec.LookPath("fuse-overlayfs"); err == nil { + opts.GraphDriverName = "overlay" + opts.GraphDriverOptions = []string{fmt.Sprintf("overlay.mount_program=%s", path)} + } else { + opts.GraphDriverName = "vfs" + } return opts, nil } diff --git a/test/e2e/pause_test.go b/test/e2e/pause_test.go index 1a2eb1a09..e80915670 100644 --- a/test/e2e/pause_test.go +++ b/test/e2e/pause_test.go @@ -91,7 +91,7 @@ var _ = Describe("Podman pause", func() { }) - It("podman remove a paused container by id", func() { + It("podman remove a paused container by id without force", func() { session := podmanTest.RunTopContainer("") session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -111,25 +111,26 @@ var _ = Describe("Podman pause", func() { Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.GetContainerStatus()).To(ContainSubstring(pausedState)) - result = podmanTest.Podman([]string{"rm", "--force", cid}) - result.WaitWithDefaultTimeout() + }) - Expect(result.ExitCode()).To(Equal(125)) - Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) - Expect(podmanTest.GetContainerStatus()).To(ContainSubstring(pausedState)) + It("podman remove a paused container by id with force", func() { + session := podmanTest.RunTopContainer("") + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + cid := session.OutputToString() - result = podmanTest.Podman([]string{"unpause", cid}) + result := podmanTest.Podman([]string{"pause", cid}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) - Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + Expect(podmanTest.GetContainerStatus()).To(ContainSubstring(pausedState)) result = podmanTest.Podman([]string{"rm", "--force", cid}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) - }) It("podman stop a paused container by id", func() { diff --git a/troubleshooting.md b/troubleshooting.md index c2edae219..574196a69 100644 --- a/troubleshooting.md +++ b/troubleshooting.md @@ -101,3 +101,29 @@ the first path in the error message Podman gave (in this case, `/run/user/1000/run`). --- +### 4) rootless containers cannot ping hosts + +When using the ping command from a non-root container, the command may +fail because of a lack of privileges. + +#### Symptom + +```console +$ podman run --rm fedora ping -W10 -c1 redhat.com +PING redhat.com (209.132.183.105): 56 data bytes + +--- redhat.com ping statistics --- +1 packets transmitted, 0 packets received, 100% packet loss +``` + +#### Solution + +It is most likely necessary to enable unprivileged pings on the host. +Be sure the UID of the user is part of the range in the +`/proc/sys/net/ipv4/ping_group_range` file. + +To change its value you can use something like: `sysctl -w +"net.ipv4.ping_group_range=0 2000000"`. + +To make the change persistent, you'll need to add a file in +`/etc/sysctl.d` that contains `net.ipv4.ping_group_range=0 $MAX_UID`. diff --git a/version/version.go b/version/version.go index 0fd4e5aeb..01b9b7a8d 100644 --- a/version/version.go +++ b/version/version.go @@ -4,4 +4,4 @@ package version // NOTE: remember to bump the version at the top // of the top-level README.md file when this is // bumped. -const Version = "0.10.2-dev" +const Version = "0.11.2-dev" |