summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--cmd/podman/containers/commit.go1
-rw-r--r--contrib/modules-load.d/podman-iptables.conf5
-rw-r--r--docs/source/markdown/podman-commit.1.md5
-rw-r--r--docs/source/markdown/podman-generate-systemd.1.md2
-rw-r--r--libpod/container_commit.go2
-rw-r--r--pkg/api/handlers/compat/images.go2
-rw-r--r--pkg/api/handlers/libpod/images.go2
-rw-r--r--pkg/api/server/register_images.go4
-rw-r--r--pkg/bindings/containers/types.go1
-rw-r--r--pkg/bindings/containers/types_commit_options.go15
-rw-r--r--pkg/domain/entities/containers.go1
-rw-r--r--pkg/domain/infra/abi/containers.go1
-rw-r--r--pkg/domain/infra/tunnel/containers.go2
-rw-r--r--pkg/specgen/generate/kube/kube.go48
-rw-r--r--pkg/specgen/generate/kube/play_test.go79
-rw-r--r--podman.spec.rpkg6
-rw-r--r--test/e2e/commit_test.go18
-rw-r--r--troubleshooting.md19
19 files changed, 215 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index 0a5389ce9..cb230d8e9 100644
--- a/Makefile
+++ b/Makefile
@@ -44,6 +44,7 @@ MANDIR ?= ${PREFIX}/share/man
SHAREDIR_CONTAINERS ?= ${PREFIX}/share/containers
ETCDIR ?= ${PREFIX}/etc
TMPFILESDIR ?= ${PREFIX}/lib/tmpfiles.d
+MODULESLOADDIR ?= ${PREFIX}/lib/modules-load.d
SYSTEMDDIR ?= ${PREFIX}/lib/systemd/system
USERSYSTEMDDIR ?= ${PREFIX}/lib/systemd/user
REMOTETAGS ?= remote exclude_graphdriver_btrfs btrfs_noversion exclude_graphdriver_devicemapper containers_image_openpgp
@@ -779,6 +780,11 @@ install.bin:
install ${SELINUXOPT} -m 755 -d ${DESTDIR}${TMPFILESDIR}
install ${SELINUXOPT} -m 644 contrib/tmpfile/podman.conf ${DESTDIR}${TMPFILESDIR}/podman.conf
+.PHONY: install.modules-load
+install.modules-load: # This should only be used by distros which might use iptables-legacy, this is not needed on RHEL
+ install ${SELINUXOPT} -m 755 -d ${DESTDIR}${MODULESLOADDIR}
+ install ${SELINUXOPT} -m 644 contrib/modules-load.d/podman-iptables.conf ${DESTDIR}${MODULESLOADDIR}/podman-iptables.conf
+
.PHONY: install.man
install.man:
install ${SELINUXOPT} -d -m 755 $(DESTDIR)$(MANDIR)/man1
diff --git a/cmd/podman/containers/commit.go b/cmd/podman/containers/commit.go
index f74fd4ab1..e0cadd5b0 100644
--- a/cmd/podman/containers/commit.go
+++ b/cmd/podman/containers/commit.go
@@ -77,6 +77,7 @@ func commitFlags(cmd *cobra.Command) {
flags.BoolVarP(&commitOptions.Pause, "pause", "p", false, "Pause container during commit")
flags.BoolVarP(&commitOptions.Quiet, "quiet", "q", false, "Suppress output")
+ flags.BoolVarP(&commitOptions.Squash, "squash", "s", false, "squash newly built layers into a single new layer")
flags.BoolVar(&commitOptions.IncludeVolumes, "include-volumes", false, "Include container volumes as image volumes")
}
diff --git a/contrib/modules-load.d/podman-iptables.conf b/contrib/modules-load.d/podman-iptables.conf
new file mode 100644
index 000000000..001ef8af8
--- /dev/null
+++ b/contrib/modules-load.d/podman-iptables.conf
@@ -0,0 +1,5 @@
+# On fedora 36 ip_tables is no longer auto loaded and rootless user have no permsissions to load it.
+# When we have actual nftables support in the future we might want to revisit this.
+# If you use iptables-nft this is not needed.
+ip_tables
+ip6_tables
diff --git a/docs/source/markdown/podman-commit.1.md b/docs/source/markdown/podman-commit.1.md
index 87b7e8aea..df3c38711 100644
--- a/docs/source/markdown/podman-commit.1.md
+++ b/docs/source/markdown/podman-commit.1.md
@@ -60,6 +60,11 @@ Set commit message for committed image.\
Pause the container when creating an image.\
The default is **false**.
+#### **--squash**, **-s**
+
+Squash newly built layers into a single new layer.\
+The default is **false**.
+
#### **--quiet**, **-q**
Suppresses output.\
diff --git a/docs/source/markdown/podman-generate-systemd.1.md b/docs/source/markdown/podman-generate-systemd.1.md
index fdc9c21a5..b2b5ee2ca 100644
--- a/docs/source/markdown/podman-generate-systemd.1.md
+++ b/docs/source/markdown/podman-generate-systemd.1.md
@@ -10,6 +10,8 @@ podman\-generate\-systemd - Generate systemd unit file(s) for a container or pod
**podman generate systemd** will create a systemd unit file that can be used to control a container or pod.
By default, the command will print the content of the unit files to stdout.
+Generating unit files for a pod requires the pod to be created with an infra container (see `--infra=true`). An infra container runs across the entire lifespan of a pod and is hence required for systemd to manage the life cycle of the pod's main unit.
+
_Note: If you use this command with the remote client, including Mac and Windows (excluding WSL2) machines, you would still have to place the generated units on the remote system. Moreover, please make sure that the XDG_RUNTIME_DIR environment variable is set. If unset, you may set it via `export XDG_RUNTIME_DIR=/run/user/$(id -u)`._
## OPTIONS
diff --git a/libpod/container_commit.go b/libpod/container_commit.go
index 99d08ccf1..7018ee7d8 100644
--- a/libpod/container_commit.go
+++ b/libpod/container_commit.go
@@ -27,6 +27,7 @@ type ContainerCommitOptions struct {
Author string
Message string
Changes []string
+ Squash bool
}
// Commit commits the changes between a container and its image, creating a new
@@ -63,6 +64,7 @@ func (c *Container) Commit(ctx context.Context, destImage string, options Contai
commitOptions := buildah.CommitOptions{
SignaturePolicyPath: options.SignaturePolicyPath,
ReportWriter: options.ReportWriter,
+ Squash: options.Squash,
SystemContext: c.runtime.imageContext,
PreferredManifestType: options.PreferredManifestType,
}
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index 3546f88a0..edefce010 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -102,6 +102,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
Comment string `schema:"comment"`
Container string `schema:"container"`
Pause bool `schema:"pause"`
+ Squash bool `schema:"squash"`
Repo string `schema:"repo"`
Tag string `schema:"tag"`
// fromSrc string # fromSrc is currently unused
@@ -138,6 +139,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
options.Message = query.Comment
options.Author = query.Author
options.Pause = query.Pause
+ options.Squash = query.Squash
for _, change := range query.Changes {
options.Changes = append(options.Changes, strings.Split(change, "\n")...)
}
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index f078c13cc..eb9fb12a6 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -497,6 +497,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
Container string `schema:"container"`
Format string `schema:"format"`
Pause bool `schema:"pause"`
+ Squash bool `schema:"squash"`
Repo string `schema:"repo"`
Tag string `schema:"tag"`
}{
@@ -543,6 +544,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
options.Message = query.Comment
options.Author = query.Author
options.Pause = query.Pause
+ options.Squash = query.Squash
options.Changes = query.Changes
ctr, err := runtime.LookupContainer(query.Container)
if err != nil {
diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go
index d7bc17093..017310f12 100644
--- a/pkg/api/server/register_images.go
+++ b/pkg/api/server/register_images.go
@@ -460,6 +460,10 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// name: changes
// type: string
// description: instructions to apply while committing in Dockerfile format
+ // - in: query
+ // name: squash
+ // type: boolean
+ // description: squash newly built layers into a single new layer
// produces:
// - application/json
// responses:
diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go
index 4915e3e23..66b90af9b 100644
--- a/pkg/bindings/containers/types.go
+++ b/pkg/bindings/containers/types.go
@@ -30,6 +30,7 @@ type CommitOptions struct {
Comment *string
Format *string
Pause *bool
+ Squash *bool
Repo *string
Tag *string
}
diff --git a/pkg/bindings/containers/types_commit_options.go b/pkg/bindings/containers/types_commit_options.go
index 7eb04198f..7b4745eb8 100644
--- a/pkg/bindings/containers/types_commit_options.go
+++ b/pkg/bindings/containers/types_commit_options.go
@@ -92,6 +92,21 @@ func (o *CommitOptions) GetPause() bool {
return *o.Pause
}
+// WithSquash set field Squash to given value
+func (o *CommitOptions) WithSquash(value bool) *CommitOptions {
+ o.Squash = &value
+ return o
+}
+
+// GetSquash returns value of field Squash
+func (o *CommitOptions) GetSquash() bool {
+ if o.Squash == nil {
+ var z bool
+ return z
+ }
+ return *o.Squash
+}
+
// WithRepo set field Repo to given value
func (o *CommitOptions) WithRepo(value string) *CommitOptions {
o.Repo = &value
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index e9bce0eb7..79795a221 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -154,6 +154,7 @@ type CommitOptions struct {
Message string
Pause bool
Quiet bool
+ Squash bool
Writer io.Writer
}
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 92f5b1a80..e6feb7c82 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -529,6 +529,7 @@ func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string,
Message: options.Message,
Changes: options.Changes,
Author: options.Author,
+ Squash: options.Squash,
}
newImage, err := ctr.Commit(ctx, options.ImageName, opts)
if err != nil {
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index aa4baf846..fe986361b 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -302,7 +302,7 @@ func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string,
return nil, errors.Errorf("invalid image name %q", opts.ImageName)
}
}
- options := new(containers.CommitOptions).WithAuthor(opts.Author).WithChanges(opts.Changes).WithComment(opts.Message)
+ options := new(containers.CommitOptions).WithAuthor(opts.Author).WithChanges(opts.Changes).WithComment(opts.Message).WithSquash(opts.Squash)
options.WithFormat(opts.Format).WithPause(opts.Pause).WithRepo(repo).WithTag(tag)
response, err := containers.Commit(ic.ClientCtx, nameOrID, options)
if err != nil {
diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go
index 767589ead..5e6671231 100644
--- a/pkg/specgen/generate/kube/kube.go
+++ b/pkg/specgen/generate/kube/kube.go
@@ -7,6 +7,7 @@ import (
"math"
"net"
"regexp"
+ "runtime"
"strconv"
"strings"
"time"
@@ -22,6 +23,7 @@ import (
"github.com/containers/podman/v4/pkg/specgen"
"github.com/containers/podman/v4/pkg/specgen/generate"
"github.com/containers/podman/v4/pkg/util"
+ "github.com/docker/docker/pkg/system"
"github.com/docker/go-units"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
@@ -712,8 +714,12 @@ func envVarValueResourceFieldRef(env v1.EnvVar, opts *CtrSpecGenOptions) (*strin
divisor.Set(1)
}
+ resources, err := getContainerResources(opts.Container)
+ if err != nil {
+ return nil, err
+ }
+
var value *resource.Quantity
- resources := opts.Container.Resources
resourceName := env.ValueFrom.ResourceFieldRef.Resource
var isValidDivisor bool
@@ -769,6 +775,46 @@ func isCPUDivisor(divisor resource.Quantity) bool {
}
}
+func getContainerResources(container v1.Container) (v1.ResourceRequirements, error) {
+ result := v1.ResourceRequirements{
+ Limits: v1.ResourceList{},
+ Requests: v1.ResourceList{},
+ }
+
+ limits := container.Resources.Limits
+ requests := container.Resources.Requests
+
+ if limits == nil || limits.Memory().IsZero() {
+ mi, err := system.ReadMemInfo()
+ if err != nil {
+ return result, err
+ }
+ result.Limits[v1.ResourceMemory] = *resource.NewQuantity(mi.MemTotal, resource.DecimalSI)
+ } else {
+ result.Limits[v1.ResourceMemory] = limits[v1.ResourceMemory]
+ }
+
+ if limits == nil || limits.Cpu().IsZero() {
+ result.Limits[v1.ResourceCPU] = *resource.NewQuantity(int64(runtime.NumCPU()), resource.DecimalSI)
+ } else {
+ result.Limits[v1.ResourceCPU] = limits[v1.ResourceCPU]
+ }
+
+ if requests == nil || requests.Memory().IsZero() {
+ result.Requests[v1.ResourceMemory] = result.Limits[v1.ResourceMemory]
+ } else {
+ result.Requests[v1.ResourceMemory] = requests[v1.ResourceMemory]
+ }
+
+ if requests == nil || requests.Cpu().IsZero() {
+ result.Requests[v1.ResourceCPU] = result.Limits[v1.ResourceCPU]
+ } else {
+ result.Requests[v1.ResourceCPU] = requests[v1.ResourceCPU]
+ }
+
+ return result, nil
+}
+
// getPodPorts converts a slice of kube container descriptions to an
// array of portmapping
func getPodPorts(containers []v1.Container) []types.PortMapping {
diff --git a/pkg/specgen/generate/kube/play_test.go b/pkg/specgen/generate/kube/play_test.go
index 282324310..6798fdb1b 100644
--- a/pkg/specgen/generate/kube/play_test.go
+++ b/pkg/specgen/generate/kube/play_test.go
@@ -6,10 +6,12 @@ import (
"io/ioutil"
"math"
"os"
+ "runtime"
"strconv"
"testing"
"github.com/containers/common/pkg/secrets"
+ "github.com/docker/docker/pkg/system"
"github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
@@ -193,6 +195,11 @@ func TestEnvVarValue(t *testing.T) {
assert.NoError(t, err)
defer os.RemoveAll(d)
secretsManager := createSecrets(t, d)
+ stringNumCPUs := strconv.Itoa(runtime.NumCPU())
+
+ mi, err := system.ReadMemInfo()
+ assert.Nil(t, err)
+ stringMemTotal := strconv.FormatInt(mi.MemTotal, 10)
tests := []struct {
name string
@@ -694,6 +701,78 @@ func TestEnvVarValue(t *testing.T) {
true,
strconv.Itoa(int(float64(cpuInt) / 0.001)),
},
+ {
+ "ResourceFieldRefNoLimitMemory",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ ResourceFieldRef: &v1.ResourceFieldSelector{
+ Resource: "limits.memory",
+ },
+ },
+ },
+ CtrSpecGenOptions{
+ Container: v1.Container{
+ Name: "test",
+ },
+ },
+ true,
+ stringMemTotal,
+ },
+ {
+ "ResourceFieldRefNoRequestMemory",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ ResourceFieldRef: &v1.ResourceFieldSelector{
+ Resource: "requests.memory",
+ },
+ },
+ },
+ CtrSpecGenOptions{
+ Container: v1.Container{
+ Name: "test",
+ },
+ },
+ true,
+ stringMemTotal,
+ },
+ {
+ "ResourceFieldRefNoLimitCPU",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ ResourceFieldRef: &v1.ResourceFieldSelector{
+ Resource: "limits.cpu",
+ },
+ },
+ },
+ CtrSpecGenOptions{
+ Container: v1.Container{
+ Name: "test",
+ },
+ },
+ true,
+ stringNumCPUs,
+ },
+ {
+ "ResourceFieldRefNoRequestCPU",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ ResourceFieldRef: &v1.ResourceFieldSelector{
+ Resource: "requests.cpu",
+ },
+ },
+ },
+ CtrSpecGenOptions{
+ Container: v1.Container{
+ Name: "test",
+ },
+ },
+ true,
+ stringNumCPUs,
+ },
}
for _, test := range tests {
diff --git a/podman.spec.rpkg b/podman.spec.rpkg
index d02b7ea99..f810d0307 100644
--- a/podman.spec.rpkg
+++ b/podman.spec.rpkg
@@ -206,6 +206,9 @@ PODMAN_VERSION=%{version} %{__make} DESTDIR=%{buildroot} PREFIX=%{_prefix} ETCDI
install.docker \
install.docker-docs \
install.remote \
+%if 0%{?fedora} >= 36
+ install.modules-load
+%endif
install -d -p %{buildroot}/%{_datadir}/%{name}/test/system
cp -pav test/system %{buildroot}/%{_datadir}/%{name}/test/
@@ -242,6 +245,9 @@ done
%{_userunitdir}/%{name}.socket
%{_userunitdir}/%{name}-restart.service
%{_usr}/lib/tmpfiles.d/%{name}.conf
+%if 0%{?fedora} >= 36
+ %{_usr}/lib/modules-load.d/%{name}-iptables.conf
+%endif
%files docker
%{_bindir}/docker
diff --git a/test/e2e/commit_test.go b/test/e2e/commit_test.go
index 495e31520..6bcf17bfe 100644
--- a/test/e2e/commit_test.go
+++ b/test/e2e/commit_test.go
@@ -4,6 +4,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
+ "strings"
. "github.com/containers/podman/v4/test/utils"
. "github.com/onsi/ginkgo"
@@ -133,6 +134,23 @@ var _ = Describe("Podman commit", func() {
Expect(foundBlue).To(Equal(true))
})
+ It("podman commit container with --squash", func() {
+ test := podmanTest.Podman([]string{"run", "--name", "test1", "-d", ALPINE, "ls"})
+ test.WaitWithDefaultTimeout()
+ Expect(test).Should(Exit(0))
+ Expect(podmanTest.NumberOfContainers()).To(Equal(1))
+
+ session := podmanTest.Podman([]string{"commit", "--squash", "test1", "foobar.com/test1-image:latest"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"inspect", "--format", "{{.RootFS.Layers}}", "foobar.com/test1-image:latest"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ // Check for one layers
+ Expect(strings.Fields(session.OutputToString())).To(HaveLen(1))
+ })
+
It("podman commit container with change flag and JSON entrypoint with =", func() {
test := podmanTest.Podman([]string{"run", "--name", "test1", "-d", ALPINE, "ls"})
test.WaitWithDefaultTimeout()
diff --git a/troubleshooting.md b/troubleshooting.md
index dedcf6bb9..8bce8e50f 100644
--- a/troubleshooting.md
+++ b/troubleshooting.md
@@ -914,10 +914,25 @@ Error: error creating tmpdir: mkdir /run/user/1000: permission denied
Podman expects a valid login session for the `rootless+cgroupv2` use-case. Podman execution is expected to fail if the login session is not present. In most cases, podman will figure out a solution on its own but if `XDG_RUNTIME_DIR` is pointing to a path that is not writable execution will most fail. Typical scenarious of such cases are seen when users are trying to use Podman with `su - <user> -c '<podman-command>`, or `sudo -l` and badly configured systemd session.
-Resolution steps
+Alternatives:
+
+* Execute Podman via __systemd-run__ that will first start a systemd login session:
+
+ ```
+ sudo systemd-run --machine=username@ --quiet --user --collect --pipe --wait podman run --rm docker.io/library/alpine echo hello
+ ```
+* Start an interactive shell in a systemd login session with the command `machinectl shell <username>@`
+ and then run Podman
+
+ ```
+ $ sudo -i
+ # machinectl shell username@
+ Connected to the local host. Press ^] three times within 1s to exit session.
+ $ podman run --rm docker.io/library/alpine echo hello
+ ```
+* Start a new systemd login session by logging in with `ssh` i.e. `ssh <username>@localhost` and then run Podman.
* Before invoking Podman command create a valid login session for your rootless user using `loginctl enable-linger <username>`
-* If `loginctl` is unavailable you can also try logging in via `ssh` i.e `ssh <username>@localhost`.
### 31) 127.0.0.1:7777 port already bound