diff options
40 files changed, 469 insertions, 307 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index ccc78717e..b1aa1b475 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -61,7 +61,7 @@ env: SPECIALMODE: "none" # don't do anything special TEST_REMOTE_CLIENT: 'false' # don't test remote client by default ADD_SECOND_PARTITION: 'false' # will certainly fail inside containers - MOD_LIBPOD_CONF: 'true' # Update libpod.conf runtime if required by OS environment + MOD_CONTAINERS_CONF: 'true' # Update containers.conf runtime if required by OS environment #### #### Credentials and other secret-sauces, decrypted at runtime when authorized. @@ -286,7 +286,7 @@ build_each_commit_task: memory: "8Gb" env: - MOD_LIBPOD_CONF: 'false' + MOD_CONTAINERS_CONF: 'false' timeout_in: 30m @@ -318,7 +318,7 @@ build_without_cgo_task: memory: "8Gb" env: - MOD_LIBPOD_CONF: 'false' + MOD_CONTAINERS_CONF: 'false' timeout_in: 30m @@ -512,7 +512,7 @@ special_testing_in_podman_task: env: ADD_SECOND_PARTITION: 'true' - MOD_LIBPOD_CONF: 'false' # Use existing/native setup + MOD_CONTAINERS_CONF: 'false' # Use existing/native setup SPECIALMODE: 'in_podman' # See docs timeout_in: 60m @@ -263,6 +263,7 @@ clean: ## Clean artifacts libpod/container_easyjson.go \ libpod/pod_easyjson.go \ docs/build + make -C docs clean .PHONY: libpodimage libpodimage: ## Build the libpod image @@ -306,6 +307,7 @@ testunit: libpodimage ## Run unittest on the built image .PHONY: localunit localunit: test/goecho/goecho varlink_generate + hack/check_root.sh make localunit ginkgo \ -r \ $(TESTFLAGS) \ diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go index 08099da4b..416c6f6ec 100644 --- a/cmd/podman/common/specgen.go +++ b/cmd/podman/common/specgen.go @@ -531,12 +531,13 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string // Only add read-only tmpfs mounts in case that we are read-only and the // read-only tmpfs flag has been set. - mounts, volumes, err := parseVolumes(c.Volume, c.Mount, c.TmpFS, c.ReadOnlyTmpFS && c.ReadOnly) + mounts, volumes, overlayVolumes, err := parseVolumes(c.Volume, c.Mount, c.TmpFS, c.ReadOnlyTmpFS && c.ReadOnly) if err != nil { return err } s.Mounts = mounts s.Volumes = volumes + s.OverlayVolumes = overlayVolumes for _, dev := range c.Devices { s.Devices = append(s.Devices, specs.LinuxDevice{Path: dev}) diff --git a/cmd/podman/common/volumes.go b/cmd/podman/common/volumes.go index b201786f0..47a6f3c35 100644 --- a/cmd/podman/common/volumes.go +++ b/cmd/podman/common/volumes.go @@ -34,43 +34,43 @@ var ( // Does not handle image volumes, init, and --volumes-from flags. // Can also add tmpfs mounts from read-only tmpfs. // TODO: handle options parsing/processing via containers/storage/pkg/mount -func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bool) ([]spec.Mount, []*specgen.NamedVolume, error) { +func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bool) ([]spec.Mount, []*specgen.NamedVolume, []*specgen.OverlayVolume, error) { // Get mounts from the --mounts flag. unifiedMounts, unifiedVolumes, err := getMounts(mountFlag) if err != nil { - return nil, nil, err + return nil, nil, nil, err } // Next --volumes flag. - volumeMounts, volumeVolumes, err := getVolumeMounts(volumeFlag) + volumeMounts, volumeVolumes, overlayVolumes, err := getVolumeMounts(volumeFlag) if err != nil { - return nil, nil, err + return nil, nil, nil, err } // Next --tmpfs flag. tmpfsMounts, err := getTmpfsMounts(tmpfsFlag) if err != nil { - return nil, nil, err + return nil, nil, nil, err } // Unify mounts from --mount, --volume, --tmpfs. // Start with --volume. for dest, mount := range volumeMounts { if _, ok := unifiedMounts[dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, dest) + return nil, nil, nil, errors.Wrapf(errDuplicateDest, dest) } unifiedMounts[dest] = mount } for dest, volume := range volumeVolumes { if _, ok := unifiedVolumes[dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, dest) + return nil, nil, nil, errors.Wrapf(errDuplicateDest, dest) } unifiedVolumes[dest] = volume } // Now --tmpfs for dest, tmpfs := range tmpfsMounts { if _, ok := unifiedMounts[dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, dest) + return nil, nil, nil, errors.Wrapf(errDuplicateDest, dest) } unifiedMounts[dest] = tmpfs } @@ -101,15 +101,29 @@ func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bo } } - // Check for conflicts between named volumes and mounts + // Check for conflicts between named volumes, overlay volumes, and mounts for dest := range unifiedMounts { if _, ok := unifiedVolumes[dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest) + return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest) + } + if _, ok := overlayVolumes[dest]; ok { + return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest) } } for dest := range unifiedVolumes { if _, ok := unifiedMounts[dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest) + return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest) + } + if _, ok := overlayVolumes[dest]; ok { + return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest) + } + } + for dest := range overlayVolumes { + if _, ok := unifiedMounts[dest]; ok { + return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest) + } + if _, ok := unifiedVolumes[dest]; ok { + return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest) } } @@ -119,7 +133,7 @@ func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bo if mount.Type == TypeBind { absSrc, err := filepath.Abs(mount.Source) if err != nil { - return nil, nil, errors.Wrapf(err, "error getting absolute path of %s", mount.Source) + return nil, nil, nil, errors.Wrapf(err, "error getting absolute path of %s", mount.Source) } mount.Source = absSrc } @@ -129,8 +143,12 @@ func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bo for _, volume := range unifiedVolumes { finalVolumes = append(finalVolumes, volume) } + finalOverlayVolume := make([]*specgen.OverlayVolume, 0) + for _, volume := range overlayVolumes { + finalOverlayVolume = append(finalOverlayVolume, volume) + } - return finalMounts, finalVolumes, nil + return finalMounts, finalVolumes, finalOverlayVolume, nil } // getMounts takes user-provided input from the --mount flag and creates OCI @@ -465,9 +483,10 @@ func getNamedVolume(args []string) (*specgen.NamedVolume, error) { return newVolume, nil } -func getVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*specgen.NamedVolume, error) { +func getVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*specgen.NamedVolume, map[string]*specgen.OverlayVolume, error) { mounts := make(map[string]spec.Mount) volumes := make(map[string]*specgen.NamedVolume) + overlayVolumes := make(map[string]*specgen.OverlayVolume) volumeFormatErr := errors.Errorf("incorrect volume format, should be [host-dir:]ctr-dir[:option]") @@ -481,7 +500,7 @@ func getVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*sp splitVol := strings.Split(vol, ":") if len(splitVol) > 3 { - return nil, nil, errors.Wrapf(volumeFormatErr, vol) + return nil, nil, nil, errors.Wrapf(volumeFormatErr, vol) } src = splitVol[0] @@ -496,34 +515,54 @@ func getVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*sp } if len(splitVol) > 2 { if options, err = parse.ValidateVolumeOpts(strings.Split(splitVol[2], ",")); err != nil { - return nil, nil, err + return nil, nil, nil, err } } // Do not check source dir for anonymous volumes if len(splitVol) > 1 { if err := parse.ValidateVolumeHostDir(src); err != nil { - return nil, nil, err + return nil, nil, nil, err } } if err := parse.ValidateVolumeCtrDir(dest); err != nil { - return nil, nil, err + return nil, nil, nil, err } cleanDest := filepath.Clean(dest) if strings.HasPrefix(src, "/") || strings.HasPrefix(src, ".") { // This is not a named volume - newMount := spec.Mount{ - Destination: cleanDest, - Type: string(TypeBind), - Source: src, - Options: options, + overlayFlag := false + for _, o := range options { + if o == "O" { + overlayFlag = true + if len(options) > 1 { + return nil, nil, nil, errors.New("can't use 'O' with other options") + } + } } - if _, ok := mounts[newMount.Destination]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, newMount.Destination) + if overlayFlag { + // This is a overlay volume + newOverlayVol := new(specgen.OverlayVolume) + newOverlayVol.Destination = cleanDest + newOverlayVol.Source = src + if _, ok := overlayVolumes[newOverlayVol.Destination]; ok { + return nil, nil, nil, errors.Wrapf(errDuplicateDest, newOverlayVol.Destination) + } + overlayVolumes[newOverlayVol.Destination] = newOverlayVol + } else { + newMount := spec.Mount{ + Destination: cleanDest, + Type: string(TypeBind), + Source: src, + Options: options, + } + if _, ok := mounts[newMount.Destination]; ok { + return nil, nil, nil, errors.Wrapf(errDuplicateDest, newMount.Destination) + } + mounts[newMount.Destination] = newMount } - mounts[newMount.Destination] = newMount } else { // This is a named volume newNamedVol := new(specgen.NamedVolume) @@ -532,7 +571,7 @@ func getVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*sp newNamedVol.Options = options if _, ok := volumes[newNamedVol.Dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, newNamedVol.Dest) + return nil, nil, nil, errors.Wrapf(errDuplicateDest, newNamedVol.Dest) } volumes[newNamedVol.Dest] = newNamedVol } @@ -540,7 +579,7 @@ func getVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*sp logrus.Debugf("User mount %s:%s options %v", src, dest, options) } - return mounts, volumes, nil + return mounts, volumes, overlayVolumes, nil } // GetTmpfsMounts creates spec.Mount structs for user-requested tmpfs mounts diff --git a/cmd/podman/registry/config.go b/cmd/podman/registry/config.go index 75e67b35d..a7e368115 100644 --- a/cmd/podman/registry/config.go +++ b/cmd/podman/registry/config.go @@ -70,7 +70,7 @@ func newPodmanConfig() { // setXdgDirs ensures the XDG_RUNTIME_DIR env and XDG_CONFIG_HOME variables are set. // containers/image uses XDG_RUNTIME_DIR to locate the auth file, XDG_CONFIG_HOME is -// use for the libpod.conf configuration file. +// use for the containers.conf configuration file. func setXdgDirs() error { if !rootless.IsRootless() { return nil diff --git a/cmd/podman/system/renumber.go b/cmd/podman/system/renumber.go index 82cf65d8f..7cec5b986 100644 --- a/cmd/podman/system/renumber.go +++ b/cmd/podman/system/renumber.go @@ -18,7 +18,7 @@ var ( podman system renumber Migrate lock numbers to handle a change in maximum number of locks. - Mandatory after the number of locks in libpod.conf is changed. + Mandatory after the number of locks in containers.conf is changed. ` renumberCommand = &cobra.Command{ diff --git a/cni/README.md b/cni/README.md index 2683df714..bc37df1eb 100644 --- a/cni/README.md +++ b/cni/README.md @@ -5,7 +5,7 @@ directory just contains an example configuration that can be used as the basis for your own configuration. To use this configuration, place it in `/etc/cni/net.d` (or the directory -specified by `cni_config_dir` in your `libpod.conf`). +specified by `cni_config_dir` in your `containers.conf`). For example a basic network configuration can be achieved with: @@ -14,4 +14,4 @@ sudo mkdir -p /etc/cni/net.d curl -qsSL https://raw.githubusercontent.com/containers/libpod/master/cni/87-podman-bridge.conflist | sudo tee /etc/cni/net.d/87-podman-bridge.conf ``` -Dependent upon your CNI configuration, you will need to install as a minimum the `port` and `bridge` [CNI plugins](https://github.com/containernetworking/plugins) into `/opt/cni/bin` (or the directory specified by `cni_plugin_dir` in libpod.conf). Please refer to the [CNI](https://github.com/containernetworking) project page in GitHub for more information. +Dependent upon your CNI configuration, you will need to install as a minimum the `port` and `bridge` [CNI plugins](https://github.com/containernetworking/plugins) into `/opt/cni/bin` (or the directory specified by `cni_plugin_dir` in containers.conf). Please refer to the [CNI](https://github.com/containernetworking) project page in GitHub for more information. diff --git a/contrib/systemd/system/podman.service b/contrib/systemd/system/podman.service index eaa2ec437..4a63735a3 100644 --- a/contrib/systemd/system/podman.service +++ b/contrib/systemd/system/podman.service @@ -2,15 +2,12 @@ Description=Podman API Service Requires=podman.socket After=podman.socket -Documentation=man:podman-api(1) +Documentation=man:podman-system-service(1) StartLimitIntervalSec=0 [Service] -Type=oneshot -Environment=REGISTRIES_CONFIG_PATH=/etc/containers/registries.conf +Type=simple ExecStart=/usr/bin/podman system service -TimeoutStopSec=30 -KillMode=process [Install] WantedBy=multi-user.target diff --git a/contrib/systemd/system/podman.socket b/contrib/systemd/system/podman.socket index 8b22e31e4..397058ee4 100644 --- a/contrib/systemd/system/podman.socket +++ b/contrib/systemd/system/podman.socket @@ -1,6 +1,6 @@ [Unit] Description=Podman API Socket -Documentation=man:podman-api(1) +Documentation=man:podman-system-service(1) [Socket] ListenStream=%t/podman/podman.sock diff --git a/contrib/systemd/user b/contrib/systemd/user new file mode 120000 index 000000000..3f3d9896b --- /dev/null +++ b/contrib/systemd/user @@ -0,0 +1 @@ +./system/
\ No newline at end of file diff --git a/contrib/systemd/user/podman.service b/contrib/systemd/user/podman.service deleted file mode 100644 index eaa2ec437..000000000 --- a/contrib/systemd/user/podman.service +++ /dev/null @@ -1,17 +0,0 @@ -[Unit] -Description=Podman API Service -Requires=podman.socket -After=podman.socket -Documentation=man:podman-api(1) -StartLimitIntervalSec=0 - -[Service] -Type=oneshot -Environment=REGISTRIES_CONFIG_PATH=/etc/containers/registries.conf -ExecStart=/usr/bin/podman system service -TimeoutStopSec=30 -KillMode=process - -[Install] -WantedBy=multi-user.target -Also=podman.socket diff --git a/contrib/systemd/user/podman.socket b/contrib/systemd/user/podman.socket deleted file mode 100644 index 8b22e31e4..000000000 --- a/contrib/systemd/user/podman.socket +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description=Podman API Socket -Documentation=man:podman-api(1) - -[Socket] -ListenStream=%t/podman/podman.sock -SocketMode=0660 - -[Install] -WantedBy=sockets.target diff --git a/docs/source/markdown/libpod.conf.5.md b/docs/source/markdown/libpod.conf.5.md deleted file mode 100644 index ca45bccf6..000000000 --- a/docs/source/markdown/libpod.conf.5.md +++ /dev/null @@ -1,114 +0,0 @@ -% libpod.conf(5) - -## NAME -libpod.conf - libpod configuration file - -## DESCRIPTION -The libpod.conf file is the default configuration file for all tools using -libpod to manage containers. - -## OPTIONS - -**image_default_transport**="" - Default transport method for pulling and pushing images - -**runtime**="" - Default OCI runtime to use if nothing is specified in **runtimes** - -**runtimes** - For each OCI runtime, specify a list of paths to look for. The first one found is used. If the paths are empty or no valid path was found, then the `$PATH` environment variable will be used as the fallback. - -**conmon_path**="" - Paths to search for the conmon container manager binary. If the paths are empty or no valid path was found, then the `$PATH` environment variable will be used as the fallback. - -**conmon_env_vars**="" - Environment variables to pass into Conmon - -**cgroup_manager**="" - Specify the CGroup Manager to use; valid values are "systemd" and "cgroupfs" - -**lock_type**="" - Specify the locking mechanism to use; valid values are "shm" and "file". Change the default only if you are sure of what you are doing, in general "file" is useful only on platforms where cgo is not available for using the faster "shm" lock type. You may need to run "podman system renumber" after you change the lock type. - -**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. - - Paths listed later in the array have higher precedence (`oci-hooks(5)` discusses directory precedence). - - For the annotation conditions, libpod uses any annotations set in the generated OCI configuration. - - For the bind-mount conditions, only mounts explicitly requested by the caller via `--volume` are considered. Bind mounts that libpod inserts by default (e.g. `/dev/shm`) are not considered. - - Podman and libpod currently support an additional `precreate` state which is called before the runtime's `create` operation. Unlike the other stages, which receive the container state on their standard input, `precreate` hooks receive the proposed runtime configuration on their standard input. They may alter that configuration as they see fit, and write the altered form to their standard output. - - **WARNING**: the `precreate` hook lets you do powerful things, such as adding additional mounts to the runtime configuration. That power also makes it easy to break things. Before reporting libpod errors, try running your container with `precreate` hooks disabled to see if the problem is due to one of your hooks. - -**static_dir**="" - Directory for persistent libpod files (database, etc) - By default this will be configured relative to where containers/storage - stores containers - -**tmp_dir**="" - Directory for temporary files - Must be a tmpfs (wiped after reboot) - -**max_log_size**="" - Maximum size of log files (in bytes) - -**no_pivot_root**="" - Whether to use chroot instead of pivot_root in the runtime - -**cni_config_dir**="" - Directory containing CNI plugin configuration files - -**cni_plugin_dir**="" - Directories where CNI plugin binaries may be located - -**infra_image** = "" - Infra (pause) container image name for pod infra containers. When running a pod, we - start a `pause` process in a container to hold open the namespaces associated with the - pod. This container and process, basically sleep/pause for the lifetime of the pod. - -**infra_command**="" - Command to run the infra container - -**namespace**="" - Default libpod namespace. If libpod is joined to a namespace, it will see only containers and pods - that were created in the same namespace, and will create new containers and pods in that namespace. - The default namespace is "", which corresponds to no namespace. When no namespace is set, all - containers and pods are visible. - -**label**="true|false" - Indicates whether the containers should use label separation by default. - Can be overridden via `--security-opt label=...` on the CLI. - -**num_locks**="" - Number of locks available for containers and pods. Each created container or pod consumes one lock. - The default number available is 2048. - If this is changed, a lock renumbering must be performed, using the `podman system renumber` command. - -**volume_path**="" - Directory where named volumes will be created in using the default volume driver. - By default this will be configured relative to where containers/storage stores containers. - -**network_cmd_path**="" - Path to the command binary to use for setting up a network. It is currently only used for setting up - a slirp4netns network. If "" is used then the binary is looked up using the $PATH environment variable. - -**events_logger**="" - Default method to use when logging events. Valid values are "file", "journald", and "none". - -**detach_keys**="" - Keys sequence used for detaching a container - -## FILES - `/usr/share/containers/libpod.conf`, default libpod configuration path - - `/etc/containers/libpod.conf`, override libpod configuration path - -## HISTORY -Apr 2018, Originally compiled by Nathan Williams <nath.e.will@gmail.com> diff --git a/docs/source/markdown/podman-attach.1.md b/docs/source/markdown/podman-attach.1.md index 1ac2e49a9..cb3ffa92e 100644 --- a/docs/source/markdown/podman-attach.1.md +++ b/docs/source/markdown/podman-attach.1.md @@ -15,7 +15,7 @@ or name, either to view its ongoing output or to control it interactively. You can detach from the container (and leave it running) using a configurable key sequence. The default sequence is `ctrl-p,ctrl-q`. Configure the keys sequence using the **--detach-keys** option, or specifying -it in the **libpod.conf** file: see **libpod.conf(5)** for more information. +it in the **containers.conf** file: see **containers.conf(5)** for more information. ## OPTIONS **--detach-keys**=*sequence* @@ -55,4 +55,4 @@ $ podman attach 1234 $ podman attach --no-stdin foobar ``` ## SEE ALSO -podman(1), podman-exec(1), podman-run(1) +podman(1), podman-exec(1), podman-run(1), containers.conf(5) diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index 4466e6616..a422dd184 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -190,7 +190,7 @@ detached container with **podman attach**. When attached in the tty mode, you can detach from the container (and leave it running) using a configurable key sequence. The default sequence is `ctrl-p,ctrl-q`. Configure the keys sequence using the **--detach-keys** option, or specifying -it in the **libpod.conf** file: see **libpod.conf(5)** for more information. +it in the **containers.conf** file: see **containers.conf(5)** for more information. **--detach-keys**=*sequence* @@ -741,7 +741,7 @@ Security Options - `seccomp=unconfined` : Turn off seccomp confinement for the container - `seccomp=profile.json` : White listed syscalls seccomp Json file to be used as a seccomp filter -Note: Labeling can be disabled for all containers by setting label=false in the **libpod.conf** (`/etc/containers/libpod.conf`) file. +Note: Labeling can be disabled for all containers by setting label=false in the **containers.conf** (`/etc/containers/containers.conf` or `$HOME/.config/containers/containers.conf`) file. **--shm-size**=*size* @@ -811,7 +811,7 @@ Create a tmpfs mount Mount a temporary filesystem (`tmpfs`) mount into a container, for example: -$ podman run -d --tmpfs /tmp:rw,size=787448k,mode=1777 my_image +$ podman create -d --tmpfs /tmp:rw,size=787448k,mode=1777 my_image This command mounts a `tmpfs` at `/tmp` within the container. The supported mount options are the same as the Linux default `mount` flags. If you do not specify @@ -887,15 +887,20 @@ Set the UTS mode for the container Create a bind mount. If you specify, ` -v /HOST-DIR:/CONTAINER-DIR`, podman bind mounts `/HOST-DIR` in the host to `/CONTAINER-DIR` in the podman -container. The `OPTIONS` are a comma delimited list and can be: <sup>[[1]](#Footnote1)</sup> +container. Similarly, `-v SOURCE-VOLUME:/CONTAINER-DIR` will mount the volume +in the host to the container. If no such named volume exists, Podman will +create one. The `OPTIONS` are a comma delimited list and can be: <sup>[[1]](#Footnote1)</sup> -* [rw|ro] -* [z|Z] -* [`[r]shared`|`[r]slave`|`[r]private`] -* [`[r]bind`] -* [`noexec`|`exec`] -* [`nodev`|`dev`] -* [`nosuid`|`suid`] +The _options_ is a comma delimited list and can be: + +* **rw**|**ro** +* **z**|**Z** +* [**r**]**shared**|[**r**]**slave**|[**r**]**private** +* [**r**]**bind** +* [**no**]**exec** +* [**no**]**dev** +* [**no**]**suid** +* [**O**] The `CONTAINER-DIR` must be an absolute path such as `/src/docs`. The volume will be mounted into the container at this directory. @@ -908,18 +913,22 @@ the container is removed via the `--rm` flag or `podman rm --volumes`. If a volume source is specified, it must be a path on the host or the name of a named volume. Host paths are allowed to be absolute or relative; relative paths are resolved relative to the directory Podman is run in. Any source that does -not begin with a `.` or `/` it will be treated as the name of a named volume. +not begin with a `.` or `/` will be treated as the name of a named volume. If a volume with that name does not exist, it will be created. Volumes created -with names are not anonymous and are not removed by `--rm` and -`podman rm --volumes`. +with names are not anonymous. They are not removed by the `--rm` option and the +`podman rm --volumes` command. You can specify multiple **-v** options to mount one or more volumes into a container. -You can add `:ro` or `:rw` suffix to a volume to mount it read-only or + `Write Protected Volume Mounts` + +You can add `:ro` or `:rw` suffix to a volume to mount it read-only or read-write mode, respectively. By default, the volumes are mounted read-write. See examples. + `Labeling Volume Mounts` + Labeling systems like SELinux require that proper labels are placed on volume content mounted into a container. Without a label, the security system might prevent the processes running inside the container from using the content. By @@ -933,6 +942,37 @@ content label. Shared volume labels allow all containers to read/write content. The `Z` option tells Podman to label the content with a private unshared label. Only the current container can use a private volume. + `Overlay Volume Mounts` + + The `:O` flag tells Podman to mount the directory from the host as a +temporary storage using the `overlay file system`. The container processes +can modify content within the mountpoint which is stored in the +container storage in a separate directory. In overlay terms, the source +directory will be the lower, and the container storage directory will be the +upper. Modifications to the mount point are destroyed when the container +finishes executing, similar to a tmpfs mount point being unmounted. + + Subsequent executions of the container will see the original source directory +content, any changes from previous container executions no longer exists. + + One use case of the overlay mount is sharing the package cache from the +host into the container to allow speeding up builds. + + Note: + + - The `O` flag conflicts with other options listed above. +Content mounted into the container is labeled with the private label. + On SELinux systems, labels in the source directory must be readable +by the container label. Usually containers can read/execute `container_share_t` +and can read/write `container_file_t`. If you can not change the labels on a +source volume, SELinux container separation must be disabled for the container +to work. + - The source directory mounted into the container with an overlay mount +should not be modified, it can cause unexpected failures. It is recommended +that you do not modify the directory until the container finishes running. + + `Mounts propagation` + By default bind mounted volumes are `private`. That means any mounts done inside container will not be visible on host and vice versa. One can change this behavior by specifying a volume mount propagation property. Making a @@ -949,7 +989,7 @@ where source dir is mounted on) has to have right propagation properties. For shared volumes, source mount point has to be shared. And for slave volumes, source mount has to be either shared or slave. <sup>[[1]](#Footnote1)</sup> -If you want to recursively mount a volume and all of it's submounts into a +If you want to recursively mount a volume and all of its submounts into a container, then you can use the `rbind` option. By default the bind option is used, and submounts of the source directory will not be mounted into the container. @@ -1110,7 +1150,7 @@ b NOTE: Use the environment variable `TMPDIR` to change the temporary storage location of downloaded container images. Podman defaults to use `/var/tmp`. ## SEE ALSO -subgid(5), subuid(5), libpod.conf(5), systemd.unit(5), setsebool(8), slirp4netns(1), fuse-overlayfs(1) +**subgid**(5), **subuid**(5), **containers.conf**(5), **systemd.unit**(5), **setsebool**(8), **slirp4netns**(1), **fuse-overlayfs**(1). ## HISTORY October 2017, converted from Docker documentation to Podman by Dan Walsh for Podman <dwalsh@redhat.com> diff --git a/docs/source/markdown/podman-events.1.md b/docs/source/markdown/podman-events.1.md index abfc6e9c1..0d91cdf17 100644 --- a/docs/source/markdown/podman-events.1.md +++ b/docs/source/markdown/podman-events.1.md @@ -10,7 +10,7 @@ podman\-events - Monitor Podman events Monitor and print events that occur in Podman. Each event will include a timestamp, a type, a status, name (if applicable), and image (if applicable). The default logging -mechanism is *journald*. This can be changed in libpod.conf by changing the `events_logger` +mechanism is *journald*. This can be changed in containers.conf by changing the `events_logger` value to `file`. Only `file` and `journald` are accepted. A `none` logger is also available but this logging mechanism completely disables events; nothing will be reported by `podman events`. @@ -150,7 +150,7 @@ $ podman events --format json ``` ## SEE ALSO -podman(1) +podman(1), containers.conf(5) ## HISTORY March 2019, Originally compiled by Brent Baude <bbaude@redhat.com> diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index de1d8aff6..a7fd5a7eb 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -208,7 +208,7 @@ Specify the key sequence for detaching a container; _sequence_ is a comma-delimi in which each item can be a single character from the [a-Z] range, or **ctrl**-_value_, where _value_ is one of: **a-z** or **@^[,_**. -This option can also be set in **libpod.conf**(5) file. +This option can also be set in **containers.conf**(5) file. Specifying "" will disable this feature. The default is **ctrl-p,ctrl-q**. @@ -759,7 +759,7 @@ Security Options - **seccomp=unconfined**: Turn off seccomp confinement for the container - **seccomp**=_profile.json_: Allowed syscall list seccomp JSON file to be used as a seccomp filter -Note: Labeling can be disabled for all containers by setting **label=false** in the **libpod.conf**(5) file. +Note: Labeling can be disabled for all containers by setting **label=false** in the **containers.conf**(5) file. **--shm-size**=_number_[_unit_] @@ -936,6 +936,7 @@ The _options_ is a comma delimited list and can be: <sup>[[1]](#Footnote1)</sup> * [**no**]**exec** * [**no**]**dev** * [**no**]**suid** +* [**O**] The _container-dir_ must be an absolute path. @@ -947,7 +948,7 @@ the container is removed via the **--rm** flag or **podman rm --volumes**. If a volume source is specified, it must be a path on the host or the name of a named volume. Host paths are allowed to be absolute or relative; relative paths are resolved relative to the directory Podman is run in. Any source that does -not begin with a **.** or **/** it will be treated as the name of a named volume. +not begin with a **.** or **/** will be treated as the name of a named volume. If a volume with that name does not exist, it will be created. Volumes created with names are not anonymous and are not removed by **--rm** and **podman rm --volumes**. @@ -958,6 +959,8 @@ container. You can add **:ro** or **:rw** option to mount a volume in read-only or read-write mode, respectively. By default, the volumes are mounted read-write. + `Labeling Volume Mounts` + Labeling systems like SELinux require that proper labels are placed on volume content mounted into a container. Without a label, the security system might prevent the processes running inside the container from using the content. By @@ -969,9 +972,41 @@ objects on the shared volumes. The **z** option tells Podman that two containers share the volume content. As a result, Podman labels the content with a shared content label. Shared volume labels allow all containers to read/write content. The **Z** option tells Podman to label the content with a private unshared label. + + `Overlay Volume Mounts` + + The `:O` flag tells Podman to mount the directory from the host as a +temporary storage using the `overlay file system`. The container processes +can modify content within the mountpoint which is stored in the +container storage in a separate directory. In overlay terms, the source +directory will be the lower, and the container storage directory will be the +upper. Modifications to the mount point are destroyed when the container +finishes executing, similar to a tmpfs mount point being unmounted. + + Subsequent executions of the container will see the original source directory +content, any changes from previous container executions no longer exists. + + One use case of the overlay mount is sharing the package cache from the +host into the container to allow speeding up builds. + + Note: + + - The `O` flag conflicts with other options listed above. +Content mounted into the container is labeled with the private label. + On SELinux systems, labels in the source directory must be readable +by the container label. Usually containers can read/execute `container_share_t` +and can read/write `container_file_t`. If you can not change the labels on a +source volume, SELinux container separation must be disabled for the container +to work. + - The source directory mounted into the container with an overlay mount +should not be modified, it can cause unexpected failures. It is recommended +that you do not modify the directory until the container finishes running. + Only the current container can use a private volume. -By default bind mounted volumes are **private**. That means any mounts done + `Mounts propagation` + +By default bind mounted volumes are `private`. That means any mounts done inside container will not be visible on host and vice versa. One can change this behavior by specifying a volume mount propagation property. Making a volume shared mounts done under that volume inside container will be @@ -1220,14 +1255,16 @@ $ podman run -p 8080:80 -d -i -t fedora/httpd To mount a host directory as a container volume, specify the absolute path to the directory and the absolute path for the container directory separated by a -colon. If the source is a named volume maintained by Podman, it's recommended to -use it's name rather than the path to the volume. Otherwise the volume will be +colon. If the source is a named volume maintained by Podman, it is recommended to +use its name rather than the path to the volume. Otherwise the volume will be considered as an orphan and wiped if you execute **podman volume prune**: ``` $ podman run -v /var/db:/data1 -i -t fedora bash $ podman run -v data:/data2 -i -t fedora bash + +$ podman run -v /var/cache/dnf:/var/cache/dnf:O -ti fedora dnf -y update ``` Using **--mount** flags to mount a host directory as a container folder, specify @@ -1389,7 +1426,7 @@ b NOTE: Use the environment variable `TMPDIR` to change the temporary storage location of downloaded container images. Podman defaults to use `/var/tmp`. ## SEE ALSO -**subgid**(5), **subuid**(5), **libpod.conf**(5), **systemd.unit**(5), **setsebool**(8), **slirp4netns**(1), **fuse-overlayfs**(1). +**subgid**(5), **subuid**(5), **containers.conf**(5), **systemd.unit**(5), **setsebool**(8), **slirp4netns**(1), **fuse-overlayfs**(1). ## HISTORY September 2018, updated by Kunal Kushwaha <kushwaha_kunal_v7@lab.ntt.co.jp> @@ -1398,8 +1435,6 @@ October 2017, converted from Docker documentation to Podman by Dan Walsh for Pod November 2015, updated by Sally O'Malley <somalley@redhat.com> -July 2014, updated by Sven Dowideit <SvenDowideit@home.org.au> - June 2014, updated by Sven Dowideit <SvenDowideit@home.org.au> April 2014, Originally compiled by William Henry <whenry@redhat.com> based on docker.com source material and internal work. diff --git a/docs/source/markdown/podman-system-migrate.1.md b/docs/source/markdown/podman-system-migrate.1.md index baabfd14b..29c0ef94b 100644 --- a/docs/source/markdown/podman-system-migrate.1.md +++ b/docs/source/markdown/podman-system-migrate.1.md @@ -33,7 +33,7 @@ This can be used after a system upgrade which changes the default OCI runtime to There are no guarantees that the containers will continue to work under the new runtime, as some runtimes support differing options and configurations. ## SEE ALSO -`podman(1)`, `libpod.conf(5)`, `usermod(8)` +`podman(1)`, `containers.conf(5)`, `usermod(8)` ## HISTORY April 2019, Originally compiled by Giuseppe Scrivano (gscrivan at redhat dot com) diff --git a/docs/source/markdown/podman-system-renumber.1.md b/docs/source/markdown/podman-system-renumber.1.md index 071eefe29..51c085606 100644 --- a/docs/source/markdown/podman-system-renumber.1.md +++ b/docs/source/markdown/podman-system-renumber.1.md @@ -9,9 +9,9 @@ podman\-system\-renumber - Migrate lock numbers to handle a change in maximum nu ## DESCRIPTION **podman system renumber** renumbers locks used by containers and pods. -Each Podman container and pod is allocated a lock at creation time, up to a maximum number controlled by the **num_locks** parameter in **libpod.conf**. +Each Podman container and pod is allocated a lock at creation time, up to a maximum number controlled by the **num_locks** parameter in **containers.conf**. -When all available locks are exhausted, no further containers and pods can be created until some existing containers and pods are removed. This can be avoided by increasing the number of locks available via modifying **libpod.conf** and subsequently running **podman system renumber** to prepare the new locks (and reallocate lock numbers to fit the new struct). +When all available locks are exhausted, no further containers and pods can be created until some existing containers and pods are removed. This can be avoided by increasing the number of locks available via modifying **containers.conf** and subsequently running **podman system renumber** to prepare the new locks (and reallocate lock numbers to fit the new struct). **podman system renumber** must be called after any changes to **num_locks** - failure to do so will result in errors starting Podman as the number of locks available conflicts with the configured number of locks. @@ -20,7 +20,7 @@ When all available locks are exhausted, no further containers and pods can be cr If possible, avoid calling **podman system renumber** while there are other Podman processes running. ## SEE ALSO -`podman(1)`, `libpod.conf(5)` +`podman(1)`, `containers.conf(5)` ## HISTORY February 2019, Originally compiled by Matt Heon (mheon at redhat dot com) diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md index c45c10243..776ee7a67 100644 --- a/docs/source/markdown/podman.1.md +++ b/docs/source/markdown/podman.1.md @@ -23,7 +23,7 @@ created by the other. **--cgroup-manager**=*manager* -CGroup manager to use for container cgroups. Supported values are cgroupfs or systemd. Default is systemd unless overridden in the libpod.conf file. +The CGroup manager to use for container cgroups. Supported values are cgroupfs or systemd. Default is systemd unless overridden in the containers.conf file. Note: Setting this flag can cause certain commands to break when called on containers previously created by the other CGroup manager type. Note: CGroup manager is not supported in rootless mode when using CGroups Version V1. @@ -32,7 +32,7 @@ Note: CGroup manager is not supported in rootless mode when using CGroups Versio Path of the configuration directory for CNI networks. (Default: `/etc/cni/net.d`) **--conmon** -Path of the conmon binary (Default path is configured in `libpod.conf`) +Path of the conmon binary (Default path is configured in `containers.conf`) **--events-backend**=*type* @@ -94,7 +94,7 @@ Default state dir configured in `/etc/containers/storage.conf`. **--runtime**=*value* -Name of the OCI runtime as specified in libpod.conf or absolute path to the OCI compatible binary used to run containers. +Name of the OCI runtime as specified in containers.conf or absolute path to the OCI compatible binary used to run containers. **--storage-driver**=*value* @@ -217,11 +217,13 @@ the exit codes follow the `chroot` standard, see below: ## FILES -**libpod.conf** (`/usr/share/containers/libpod.conf`) +**containers.conf** (`/usr/share/containers/containers.conf`) - libpod.conf is the configuration file for all tools using libpod to manage containers, when run as root. Administrators can override the defaults file by creating `/etc/containers/libpod.conf`. When Podman runs in rootless mode, the file `$HOME/.config/containers/libpod.conf` is created and replaces some fields in the system configuration file. + Podman has builtin defaults for command line options. These defaults can be overridden using the containers.conf configuration files. - Podman uses builtin defaults if no libpod.conf file is found. +Distributions ship the `/usr/share/containers/containers.conf` file with their default settings. Administrators can override fields in this file by creating the `/etc/containers/containers.conf` file. Users can further modify defaults by creating the `$HOME/.config/containers/containers.conf` file. Podman merges its builtin defaults with the specified fields from these files, if they exist. Fields specified in the users file override the administrator's file, which overrides the distribution's file, which override the built-in defaults. + +Podman uses builtin defaults if no containers.conf file is found. **mounts.conf** (`/usr/share/containers/mounts.conf`) @@ -280,7 +282,7 @@ The Network File System (NFS) and other distributed file systems (for example: L For more information, please refer to the [Podman Troubleshooting Page](https://github.com/containers/libpod/blob/master/troubleshooting.md). ## SEE ALSO -`containers-mounts.conf(5)`, `containers-registries.conf(5)`, `containers-storage.conf(5)`, `buildah(1)`, `libpod.conf(5)`, `oci-hooks(5)`, `containers-policy.json(5)`, `subuid(5)`, `subgid(5)`, `slirp4netns(1)` +`containers-mounts.conf(5)`, `containers-registries.conf(5)`, `containers-storage.conf(5)`, `buildah(1)`, `containers.conf(5)`, `oci-hooks(5)`, `containers-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/rootless_tutorial.md b/docs/tutorials/rootless_tutorial.md index 440e12062..821c07647 100644 --- a/docs/tutorials/rootless_tutorial.md +++ b/docs/tutorials/rootless_tutorial.md @@ -13,7 +13,7 @@ The alternative OCI runtime support for cgroup V2 can be turned on at the comma ``` sudo podman --runtime /usr/bin/crun ``` -or by changing the value for the "Default OCI runtime" in the libpod.conf file either at the system level or at the [user level](#user-configuration-files) from `runtime = "runc"` to `runtime = "crun"`. +or by changing the value for the "Default OCI runtime" in the containers.conf file either at the system level or at the [user level](#user-configuration-files) from `runtime = "runc"` to `runtime = "crun"`. ## Administrator Actions @@ -106,7 +106,7 @@ Once the Administrator has completed the setup on the machine and then the confi ### User Configuration Files -The Podman configuration files for root reside in `/usr/share/containers` with overrides in `/etc/containers`. In the rootless environment they reside in `${XDG_CONFIG_HOME}/containers` (usually `~/.config/containers`) and are owned by each individual user. The main files are `libpod.conf` and `storage.conf` and the user can modify these files as they wish. +The Podman configuration files for root reside in `/usr/share/containers` with overrides in `/etc/containers`. In the rootless environment they reside in `${XDG_CONFIG_HOME}/containers` (usually `~/.config/containers`) and are owned by each individual user. The main files are `containers.conf` and `storage.conf` and the user can modify these files as they wish. The default authorization file used by the `podman login` and `podman logout` commands reside in `${XDG_RUNTIME_DIR}/containers/auth.json`. diff --git a/hack/check_root.sh b/hack/check_root.sh new file mode 100755 index 000000000..203eae9d3 --- /dev/null +++ b/hack/check_root.sh @@ -0,0 +1,5 @@ +#!/bin/bash +if ! [ $(id -u) = 0 ]; then + echo "Please run as root! '$@' requires root privileges." + exit 1 +fi diff --git a/libpod/container.go b/libpod/container.go index 1ca38ae7e..fda018640 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -262,6 +262,8 @@ type ContainerConfig struct { Mounts []string `json:"mounts,omitempty"` // NamedVolumes lists the named volumes to mount into the container. NamedVolumes []*ContainerNamedVolume `json:"namedVolumes,omitempty"` + // OverlayVolumes lists the overlay volumes to mount into the container. + OverlayVolumes []*ContainerOverlayVolume `json:"overlayVolumes,omitempty"` // Security Config @@ -449,6 +451,15 @@ type ContainerNamedVolume struct { Options []string `json:"options,omitempty"` } +// ContainerOverlayVolume is a overlay volume that will be mounted into the +// container. Each volume is a libpod Volume present in the state. +type ContainerOverlayVolume struct { + // Destination is the absolute path where the mount will be placed in the container. + Dest string `json:"dest"` + // Source specifies the source path of the mount. + Source string `json:"source,omitempty"` +} + // Config accessors // Unlocked diff --git a/libpod/container_internal.go b/libpod/container_internal.go index a79b9e5a8..b2e23b3a8 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -1588,6 +1588,12 @@ func (c *Container) cleanupStorage() error { } } + if err := c.cleanupOverlayMounts(); err != nil { + // If the container can't remove content report the error + logrus.Errorf("Failed to cleanup overlay mounts for %s: %v", c.ID(), err) + cleanupErr = err + } + if c.config.Rootfs != "" { return cleanupErr } diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 255505416..1c21f2ff9 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -20,6 +20,7 @@ import ( cnitypes "github.com/containernetworking/cni/pkg/types/current" "github.com/containernetworking/plugins/pkg/ns" + "github.com/containers/buildah/pkg/overlay" "github.com/containers/buildah/pkg/secrets" "github.com/containers/common/pkg/apparmor" "github.com/containers/common/pkg/config" @@ -319,6 +320,19 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { } } + // Add overlay volumes + for _, overlayVol := range c.config.OverlayVolumes { + contentDir, err := overlay.TempDir(c.config.StaticDir, c.RootUID(), c.RootGID()) + if err != nil { + return nil, errors.Wrapf(err, "failed to create TempDir in the %s directory", c.config.StaticDir) + } + overlayMount, err := overlay.Mount(contentDir, overlayVol.Source, overlayVol.Dest, c.RootUID(), c.RootGID(), c.runtime.store.GraphOptions()) + if err != nil { + return nil, errors.Wrapf(err, "creating overlay failed %q", overlayVol.Source) + } + g.AddMount(overlayMount) + } + hasHomeSet := false for _, s := range c.config.Spec.Process.Env { if strings.HasPrefix(s, "HOME=") { @@ -1642,3 +1656,7 @@ func (c *Container) copyTimezoneFile(zonePath string) (string, error) { } return localtimeCopy, err } + +func (c *Container) cleanupOverlayMounts() error { + return overlay.CleanupContent(c.config.StaticDir) +} diff --git a/libpod/container_internal_unsupported.go b/libpod/container_internal_unsupported.go index e6d94104c..b58a5116b 100644 --- a/libpod/container_internal_unsupported.go +++ b/libpod/container_internal_unsupported.go @@ -46,6 +46,10 @@ func (c *Container) getOCICgroupPath() (string, error) { return "", define.ErrNotImplemented } +func (c *Container) cleanupOverlayMounts() error { + return nil +} + func (c *Container) getUserOverrides() *lookup.Overrides { return nil } diff --git a/libpod/container_validate.go b/libpod/container_validate.go index c02833359..666ad0aca 100644 --- a/libpod/container_validate.go +++ b/libpod/container_validate.go @@ -99,5 +99,24 @@ func (c *Container) validate() error { return errors.Wrapf(define.ErrInvalidArg, "cannot add to /etc/hosts if using image's /etc/hosts") } + // Check named volume and overlay volumes destination conflits + destinations := make(map[string]bool) + for _, vol := range c.config.NamedVolumes { + // Don't check if they already exist. + // If they don't we will automatically create them. + if _, ok := destinations[vol.Dest]; ok { + return errors.Wrapf(define.ErrInvalidArg, "two volumes found with destination %s", vol.Dest) + } + destinations[vol.Dest] = true + } + for _, vol := range c.config.OverlayVolumes { + // Don't check if they already exist. + // If they don't we will automatically create them. + if _, ok := destinations[vol.Dest]; ok { + return errors.Wrapf(define.ErrInvalidArg, "two volumes found with destination %s", vol.Dest) + } + destinations[vol.Dest] = true + } + return nil } diff --git a/libpod/options.go b/libpod/options.go index 32748a3c1..40cf452db 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -1380,17 +1380,7 @@ func WithNamedVolumes(volumes []*ContainerNamedVolume) CtrCreateOption { return define.ErrCtrFinalized } - destinations := make(map[string]bool) - for _, vol := range volumes { - // Don't check if they already exist. - // If they don't we will automatically create them. - - if _, ok := destinations[vol.Dest]; ok { - return errors.Wrapf(define.ErrInvalidArg, "two volumes found with destination %s", vol.Dest) - } - destinations[vol.Dest] = true - mountOpts, err := util.ProcessOptions(vol.Options, false, "") if err != nil { return errors.Wrapf(err, "error processing options for named volume %q mounted at %q", vol.Name, vol.Dest) @@ -1407,6 +1397,25 @@ func WithNamedVolumes(volumes []*ContainerNamedVolume) CtrCreateOption { } } +// WithOverlayVolumes adds the given overlay volumes to the container. +func WithOverlayVolumes(volumes []*ContainerOverlayVolume) CtrCreateOption { + return func(ctr *Container) error { + if ctr.valid { + return define.ErrCtrFinalized + } + + for _, vol := range volumes { + + ctr.config.OverlayVolumes = append(ctr.config.OverlayVolumes, &ContainerOverlayVolume{ + Dest: vol.Dest, + Source: vol.Source, + }) + } + + return nil + } +} + // WithHealthCheck adds the healthcheck to the container config func WithHealthCheck(healthCheck *manifest.Schema2HealthConfig) CtrCreateOption { return func(ctr *Container) error { diff --git a/libpod/runtime.go b/libpod/runtime.go index 0075c0e13..96243c808 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -84,7 +84,7 @@ type Runtime struct { // SetXdgDirs ensures the XDG_RUNTIME_DIR env and XDG_CONFIG_HOME variables are set. // containers/image uses XDG_RUNTIME_DIR to locate the auth file, XDG_CONFIG_HOME is -// use for the libpod.conf configuration file. +// use for the containers.conf configuration file. func SetXdgDirs() error { if !rootless.IsRootless() { return nil @@ -577,7 +577,7 @@ func (r *Runtime) Shutdown(force bool) error { } var lastError error - // If no store was requested, it can bew nil and there is no need to + // If no store was requested, it can be nil and there is no need to // attempt to shut it down if r.store != nil { if _, err := r.store.Shutdown(force); err != nil { diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go index bedd050ff..9727f1d4e 100644 --- a/pkg/domain/infra/abi/system.go +++ b/pkg/domain/infra/abi/system.go @@ -230,13 +230,18 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System } } - named, err := reference.ParseNormalizedNamed(name) - if err != nil { - return nil, err - } - repository = named.Name() - if tagged, isTagged := named.(reference.NamedTagged); isTagged { - tag = tagged.Tag() + if len(name) > 0 { + named, err := reference.ParseNormalizedNamed(name) + if err != nil { + return nil, err + } + repository = named.Name() + if tagged, isTagged := named.(reference.NamedTagged); isTagged { + tag = tagged.Tag() + } + } else { + repository = "<none>" + tag = "<none>" } report := entities.SystemDfImageReport{ diff --git a/pkg/network/config.go b/pkg/network/config.go index e5c981419..a504e0ad0 100644 --- a/pkg/network/config.go +++ b/pkg/network/config.go @@ -6,8 +6,8 @@ import ( "net" ) -// TODO once the libpod.conf file stuff is worked out, this should be modified -// to honor defines in the libpod.conf as well as overrides? +// TODO once the containers.conf file stuff is worked out, this should be modified +// to honor defines in the containers.conf as well as overrides? const ( // CNIConfigDir is the path where CNI config files exist diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index c1ceac69e..6dbc45c16 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -201,6 +201,9 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen. for _, volume := range volumes { destinations = append(destinations, volume.Dest) } + for _, overlayVolume := range s.OverlayVolumes { + destinations = append(destinations, overlayVolume.Destination) + } options = append(options, libpod.WithUserVolumes(destinations)) if len(volumes) != 0 { @@ -215,6 +218,17 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen. options = append(options, libpod.WithNamedVolumes(vols)) } + if len(s.OverlayVolumes) != 0 { + var vols []*libpod.ContainerOverlayVolume + for _, v := range s.OverlayVolumes { + vols = append(vols, &libpod.ContainerOverlayVolume{ + Dest: v.Destination, + Source: v.Source, + }) + } + options = append(options, libpod.WithOverlayVolumes(vols)) + } + if s.Command != nil { options = append(options, libpod.WithCommand(s.Command)) } diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index a346a9742..c6079be33 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -198,6 +198,9 @@ type ContainerStorageConfig struct { // there are conflicts. // Optional. Volumes []*NamedVolume `json:"volumes,omitempty"` + // Overlay volumes are named volumes that will be added to the container. + // Optional. + OverlayVolumes []*OverlayVolume `json:"overlay_volumes,omitempty"` // Devices are devices that will be added to the container. // Optional. Devices []spec.LinuxDevice `json:"devices,omitempty"` @@ -443,6 +446,15 @@ type NamedVolume struct { Options []string } +// OverlayVolume holds information about a overlay volume that will be mounted into +// the container. +type OverlayVolume struct { + // Destination is the absolute path where the mount will be placed in the container. + Destination string `json:"destination"` + // Source specifies the source path of the mount. + Source string `json:"source,omitempty"` +} + // PortMapping is one or more ports that will be mapped into the container. type PortMapping struct { // HostIP is the IP that we will bind to on the host. diff --git a/pkg/util/mountOpts.go b/pkg/util/mountOpts.go index 416e60728..eab2657e3 100644 --- a/pkg/util/mountOpts.go +++ b/pkg/util/mountOpts.go @@ -33,6 +33,10 @@ func ProcessOptions(options []string, isTmpfs bool, sourcePath string) ([]string // Some options have parameters - size, mode splitOpt := strings.SplitN(opt, "=", 2) switch splitOpt[0] { + case "O": + if len(options) > 1 { + return nil, errors.Wrapf(ErrDupeMntOption, "'O' option can not be used with other options") + } case "exec", "noexec": if foundExec { return nil, errors.Wrapf(ErrDupeMntOption, "only one of 'noexec' and 'exec' can be used") diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go index 987e4779c..577a7562b 100644 --- a/test/e2e/generate_kube_test.go +++ b/test/e2e/generate_kube_test.go @@ -254,8 +254,6 @@ var _ = Describe("Podman generate kube", func() { }) It("podman generate with user and reimport kube on pod", func() { - // This test fails on ubuntu due to https://github.com/seccomp/containers-golang/pull/27 - SkipIfNotFedora() podName := "toppod" _, rc, _ := podmanTest.CreatePod(podName) Expect(rc).To(Equal(0)) diff --git a/test/e2e/run_device_test.go b/test/e2e/run_device_test.go index a5e1e0269..b1a4c9cb2 100644 --- a/test/e2e/run_device_test.go +++ b/test/e2e/run_device_test.go @@ -75,11 +75,17 @@ var _ = Describe("Podman run device", func() { It("podman run device host device and container device parameter are directories", func() { SkipIfRootless() - SystemExec("mkdir", []string{"/dev/foodevdir"}) - SystemExec("mknod", []string{"/dev/foodevdir/null", "c", "1", "3"}) - session := podmanTest.Podman([]string{"run", "-q", "--device", "/dev/foodevdir:/dev/bar", ALPINE, "ls", "/dev/bar/null"}) + Expect(os.MkdirAll("/dev/foodevdir", os.ModePerm)).To(BeNil()) + defer os.RemoveAll("/dev/foodevdir") + + mknod := SystemExec("mknod", []string{"/dev/foodevdir/null", "c", "1", "3"}) + mknod.WaitWithDefaultTimeout() + Expect(mknod.ExitCode()).To(Equal(0)) + + session := podmanTest.Podman([]string{"run", "-q", "--device", "/dev/foodevdir:/dev/bar", ALPINE, "stat", "-c%t:%T", "/dev/bar/null"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Equal("1:3")) }) It("podman run device host device with --privileged", func() { diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go index 92988ff87..2b806ac2b 100644 --- a/test/e2e/run_volume_test.go +++ b/test/e2e/run_volume_test.go @@ -9,6 +9,7 @@ import ( "path/filepath" "strings" + "github.com/containers/libpod/v2/pkg/rootless" . "github.com/containers/libpod/v2/test/utils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -450,4 +451,92 @@ VOLUME /test/` Expect(data[0].Mounts[0].Source).To(Equal("/tmp")) Expect(data[0].Mounts[0].Destination).To(Equal("/test")) }) + + It("podman run with overlay volume flag", func() { + if os.Getenv("container") != "" { + Skip("Overlay mounts not supported when running in a container") + } + if rootless.IsRootless() { + if _, err := exec.LookPath("fuse_overlay"); err != nil { + Skip("Fuse-Overlayfs required for rootless overlay mount test") + } + } + mountPath := filepath.Join(podmanTest.TempDir, "secrets") + os.Mkdir(mountPath, 0755) + testFile := filepath.Join(mountPath, "test1") + f, err := os.Create(testFile) + f.Close() + + // Make sure host directory gets mounted in to container as overlay + session := podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/run/test:O", mountPath), ALPINE, "grep", "/run/test", "/proc/self/mountinfo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + found, matches := session.GrepString("/run/test") + Expect(found).Should(BeTrue()) + Expect(matches[0]).To(ContainSubstring("overlay")) + + // Make sure host files show up in the container + session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/run/test:O", mountPath), ALPINE, "ls", "/run/test/test1"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + // Make sure modifications in container do not show up on host + session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:/run/test:O", mountPath), ALPINE, "touch", "/run/test/container"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + _, err = os.Stat(filepath.Join(mountPath, "container")) + Expect(err).To(Not(BeNil())) + + // Make sure modifications in container disappear when container is stopped + session = podmanTest.Podman([]string{"create", "-d", "-v", fmt.Sprintf("%s:/run/test:O", mountPath), ALPINE, "top"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + session = podmanTest.Podman([]string{"start", "-l"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + session = podmanTest.Podman([]string{"exec", "-l", "touch", "/run/test/container"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + session = podmanTest.Podman([]string{"exec", "-l", "ls", "/run/test/container"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + session = podmanTest.Podman([]string{"stop", "-l"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + session = podmanTest.Podman([]string{"start", "-l"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + session = podmanTest.Podman([]string{"exec", "-l", "ls", "/run/test/container"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + }) + + It("overlay volume conflicts with named volume and mounts", func() { + mountPath := filepath.Join(podmanTest.TempDir, "secrets") + os.Mkdir(mountPath, 0755) + testFile := filepath.Join(mountPath, "test1") + f, err := os.Create(testFile) + Expect(err).To(BeNil()) + f.Close() + mountSrc := filepath.Join(podmanTest.TempDir, "vol-test1") + err = os.MkdirAll(mountSrc, 0755) + Expect(err).To(BeNil()) + mountDest := "/run/test" + volName := "myvol" + + session := podmanTest.Podman([]string{"volume", "create", volName}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + // overlay and named volume destinations conflict + session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:%s:O", mountPath, mountDest), "-v", fmt.Sprintf("%s:%s", volName, mountDest), ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + // overlay and bind mount destinations conflict + session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:%s:O", mountPath, mountDest), "--mount", fmt.Sprintf("type=bind,src=%s,target=%s", mountSrc, mountDest), ALPINE}) + Expect(session.ExitCode()).To(Not(Equal(0))) + // overlay and tmpfs mount destinations conflict + session = podmanTest.Podman([]string{"run", "--rm", "-v", fmt.Sprintf("%s:%s:O", mountPath, mountDest), "--mount", fmt.Sprintf("type=tmpfs,target=%s", mountDest), ALPINE}) + Expect(session.ExitCode()).To(Not(Equal(0))) + }) }) diff --git a/test/e2e/system_df_test.go b/test/e2e/system_df_test.go index 16a8dbb7e..f17afaec1 100644 --- a/test/e2e/system_df_test.go +++ b/test/e2e/system_df_test.go @@ -60,4 +60,18 @@ var _ = Describe("podman system df", func() { Expect(containers[1]).To(Equal("2")) Expect(volumes[2]).To(Equal("1")) }) + + It("podman system df image with no tag", func() { + session := podmanTest.PodmanNoCache([]string{"create", ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.PodmanNoCache([]string{"image", "untag", ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.PodmanNoCache([]string{"system", "df"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) }) diff --git a/test/system/helpers.bash b/test/system/helpers.bash index 4239ef876..abca91739 100644 --- a/test/system/helpers.bash +++ b/test/system/helpers.bash @@ -404,7 +404,13 @@ function find_exec_pid_files() { # # This obviously screws us up when we look at output results. # -# This function removes the warning from $output and $lines +# This function removes the warning from $output and $lines. We don't +# do a full string match because there's another variant of that message: +# +# WARNING: Creating device "/dev/null" with same type, major and minor as existing "/dev/foodevdir/null". +# +# (We should never again see that precise error ever again, but we could +# see variants of it). # function remove_same_dev_warning() { # No input arguments. We operate in-place on $output and $lines @@ -412,7 +418,7 @@ function remove_same_dev_warning() { local i=0 local -a new_lines=() while [[ $i -lt ${#lines[@]} ]]; do - if expr "${lines[$i]}" : 'WARNING: .* same type, major.* multiple' >/dev/null; then + if expr "${lines[$i]}" : 'WARNING: .* same type, major' >/dev/null; then : else new_lines+=("${lines[$i]}") diff --git a/troubleshooting.md b/troubleshooting.md index 8175073cd..4c452404c 100644 --- a/troubleshooting.md +++ b/troubleshooting.md @@ -102,41 +102,7 @@ communicate with a registry and not use tls verification. * I.e. `podman push --tls-verify=false alpine docker://localhost:5000/myalpine:latest` --- -### 5) Rootless: could not get runtime - database configuration mismatch - -In Podman release 0.11.1, a default path for rootless containers was changed, -potentially causing rootless Podman to be unable to function. The new default -path is not a problem for new installations, but existing installations will -need to work around it with the following fix. - -#### Symptom - -```console -$ podman info -could not get runtime: database run root /run/user/1000/run does not match our run root /run/user/1000: database configuration mismatch -``` - -#### Solution - -This problem has been fixed in Podman release 0.12.1 and it is recommended -to upgrade to that version. If that is not possible use the following procedure. - -To work around the new default path, we can manually set the path Podman is -expecting in a configuration file. - -First, we need to make a new local configuration file for rootless Podman. -* `mkdir -p ~/.config/containers` -* `cp /usr/share/containers/libpod.conf ~/.config/containers` - -Next, edit the new local configuration file -(`~/.config/containers/libpod.conf`) with your favorite editor. Comment out the -line starting with `cgroup_manager` by adding a `#` character at the beginning -of the line, and change the path in the line starting with `tmp_dir` to point to -the first path in the error message Podman gave (in this case, -`/run/user/1000/tmp`). - ---- -### 6) rootless containers cannot ping hosts +### 5) 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. @@ -164,7 +130,7 @@ 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`. --- -### 7) Build hangs when the Dockerfile contains the useradd command +### 6) Build hangs when the Dockerfile contains the useradd command When the Dockerfile contains a command like `RUN useradd -u 99999000 -g users newuser` the build can hang. @@ -176,7 +142,7 @@ If you are using a useradd command within a Dockerfile with a large UID/GID, it If the entry in the Dockerfile looked like: RUN useradd -u 99999000 -g users newuser then add the `--no-log-init` parameter to change it to: `RUN useradd --no-log-init -u 99999000 -g users newuser`. This option tells useradd to stop creating the lastlog file. -### 8) Permission denied when running Podman commands +### 7) Permission denied when running Podman commands When rootless Podman attempts to execute a container on a non exec home directory a permission error will be raised. @@ -206,7 +172,7 @@ cat ~/.config/containers/storage.conf mount_program = "/bin/fuse-overlayfs" ``` -### 9) Permission denied when running systemd within a Podman container +### 8) Permission denied when running systemd within a Podman container When running systemd as PID 1 inside of a container on an SELinux separated machine, it needs to write to the cgroup file system. @@ -231,7 +197,7 @@ Only do this on systems running older versions of Podman. `setsebool -P container_manage_cgroup true` -### 10) Newuidmap missing when running rootless Podman commands +### 9) Newuidmap missing when running rootless Podman commands Rootless Podman requires the newuidmap and newgidmap programs to be installed. @@ -249,7 +215,7 @@ cannot find newuidmap: exec: "newuidmap": executable file not found in $PATH Install a version of shadow-utils that includes these executables. Note that for RHEL and CentOS 7, at least the 7.7 release must be installed for support to be available. -### 11) rootless setup user: invalid argument +### 10) rootless setup user: invalid argument Rootless Podman requires the user running it to have a range of UIDs listed in /etc/subuid and /etc/subgid. @@ -298,7 +264,7 @@ grep johndoe /etc/subuid /etc/subgid /etc/subgid:johndoe:200000:1001 ``` -### 12) Changing the location of the Graphroot leads to permission denied +### 11) Changing the location of the Graphroot leads to permission denied When I change the graphroot storage location in storage.conf, the next time I run Podman I get an error like: @@ -337,7 +303,7 @@ tells SELinux to apply the labels to the actual content. Now all new content created in these directories will automatically be created with the correct label. -### 13) Anonymous image pull fails with 'invalid username/password' +### 12) Anonymous image pull fails with 'invalid username/password' Pulling an anonymous image that doesn't require authentication can result in an `invalid username/password` error. @@ -363,7 +329,7 @@ are established locally and then the password is updated later in the container Depending upon which container tool was used to establish the credentials, use `podman logout` or `docker logout` to remove the credentials from the authentication file. -### 14) Running Podman inside a container causes container crashes and inconsistent states +### 13) Running Podman inside a container causes container crashes and inconsistent states Running Podman in a container and forwarding some, but not all, of the required host directories can cause inconsistent container behavior. @@ -381,7 +347,7 @@ This can cause Podman to reset container states and lose track of running contai For running containers on the host from inside a container, we also recommend the [Podman remote client](remote_client.md), which only requires a single socket to be mounted into the container. -### 15) Rootless 'podman build' fails EPERM on NFS: +### 14) Rootless 'podman build' fails EPERM on NFS: NFS enforces file creation on different UIDs on the server side and does not understand user namespace, which rootless Podman requires. When a container root process like YUM attempts to create a file owned by a different UID, NFS Server denies the creation. @@ -398,10 +364,10 @@ error creating build container: Error committing the finished image: error addin Choose one of the following: * Setup containers/storage in a different directory, not on an NFS share. * Create a directory on a local file system. - * Edit `~/.config/containers/libpod.conf` and point the `volume_path` option to that local directory. + * Edit `~/.config/containers/containers.conf` and point the `volume_path` option to that local directory. (Copy /usr/share/containers/containers.conf if ~/.config/containers/containers.conf does not exist) * Otherwise just run Podman as root, via `sudo podman` -### 16) Rootless 'podman build' fails when using OverlayFS: +### 15) Rootless 'podman build' fails when using OverlayFS: The Overlay file system (OverlayFS) requires the ability to call the `mknod` command when creating whiteout files when extracting an image. However, a rootless user does not have the privileges to use `mknod` in this capacity. @@ -431,7 +397,7 @@ Choose one of the following: * Install the fuse-overlayfs package for your Linux Distribution. * Add `mount_program = "/usr/bin/fuse-overlayfs"` under `[storage.options]` in your `~/.config/containers/storage.conf` file. -### 17) RHEL 7 and CentOS 7 based `init` images don't work with cgroup v2 +### 16) RHEL 7 and CentOS 7 based `init` images don't work with cgroup v2 The systemd version shipped in RHEL 7 and CentOS 7 doesn't have support for cgroup v2. Support for cgroup V2 requires version 230 of systemd or newer, which was never shipped or supported on RHEL 7 or CentOS 7. @@ -459,7 +425,7 @@ On Fedora you can do: * update the image to use an updated version of systemd. -### 18) rootless containers exit once the user session exits +### 17) rootless containers exit once the user session exits You need to set lingering mode through loginctl to prevent user processes to be killed once the user session completed. @@ -477,7 +443,7 @@ or as root if your user has not enough privileges. * sudo loginctl enable-linger $UID -### 19) `podman run` fails with "bpf create: permission denied error" +### 18) `podman run` fails with "bpf create: permission denied error" The Kernel Lockdown patches deny eBPF programs when Secure Boot is enabled in the BIOS. [Matthew Garrett's post](https://mjg59.dreamwidth.org/50577.html) describes the relationship between Lockdown and Secure Boot and [Jan-Philip Gehrcke's](https://gehrcke.de/2019/09/running-an-ebpf-program-may-require-lifting-the-kernel-lockdown/) connects this with eBPF. [RH bug 1768125](https://bugzilla.redhat.com/show_bug.cgi?id=1768125) contains some additional details. @@ -518,7 +484,7 @@ $ podman unshare cat /proc/self/uid_map Reference [subuid](http://man7.org/linux/man-pages/man5/subuid.5.html) and [subgid](http://man7.org/linux/man-pages/man5/subgid.5.html) man pages for more detail. -### 21) Passed-in device can't be accessed in rootless container +### 20) Passed-in device can't be accessed in rootless container As a non-root user you have group access rights to a device that you want to pass into a rootless container with `--device=...`. @@ -534,7 +500,7 @@ the non-root user has. If you use the `crun` runtime, 0.10.4 or newer, then you can enable a workaround by adding `--annotation io.crun.keep_original_groups=1` to the `podman` command line. -### 22) A rootless container running in detached mode is closed at logout +### 21) A rootless container running in detached mode is closed at logout When running a container with a command like `podman run --detach httpd` as a rootless user, the container is closed upon logout and is not kept running. @@ -554,7 +520,7 @@ To later revert the linger functionality, use `loginctl disable-linger`. LOGINCTL(1), SYSTEMD(1) -### 23) Containers default detach keys conflict with shell history navigation +### 22) Containers default detach keys conflict with shell history navigation Podman defaults to `ctrl-p,ctrl-q` to detach from a running containers. The bash and zsh shells default to ctrl-p for the displaying of the previous |