mirror of
https://github.com/containers/podman.git
synced 2025-12-02 02:58:03 +08:00
rootfs: Add support for rootfs-overlay and bump to buildah v1.22.1-0.202108
Allows users to specify a readonly rootfs with :O, in exchange podman will create a writable overlay. bump builah to v1.22.1-0.20210823173221-da2b428c56ce [NO TESTS NEEDED] Signed-off-by: flouthoc <flouthoc.git@gmail.com>
This commit is contained in:
244
vendor/github.com/containers/buildah/run_linux.go
generated
vendored
244
vendor/github.com/containers/buildah/run_linux.go
generated
vendored
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/containers/buildah/copier"
|
||||
"github.com/containers/buildah/define"
|
||||
"github.com/containers/buildah/pkg/overlay"
|
||||
"github.com/containers/buildah/pkg/sshagent"
|
||||
"github.com/containers/buildah/util"
|
||||
"github.com/containers/common/pkg/capabilities"
|
||||
"github.com/containers/common/pkg/chown"
|
||||
@@ -207,7 +208,7 @@ func (b *Builder) Run(command []string, options RunOptions) error {
|
||||
}
|
||||
|
||||
if !(contains(volumes, "/etc/resolv.conf") || (len(b.CommonBuildOpts.DNSServers) == 1 && strings.ToLower(b.CommonBuildOpts.DNSServers[0]) == "none")) {
|
||||
resolvFile, err := b.addNetworkConfig(path, "/etc/resolv.conf", rootIDPair, b.CommonBuildOpts.DNSServers, b.CommonBuildOpts.DNSSearch, b.CommonBuildOpts.DNSOptions, namespaceOptions)
|
||||
resolvFile, err := b.addResolvConf(path, rootIDPair, b.CommonBuildOpts.DNSServers, b.CommonBuildOpts.DNSSearch, b.CommonBuildOpts.DNSOptions, namespaceOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -246,14 +247,17 @@ rootless=%d
|
||||
|
||||
bindFiles["/run/.containerenv"] = containerenvPath
|
||||
}
|
||||
|
||||
runMountTargets, err := b.setupMounts(mountPoint, spec, path, options.Mounts, bindFiles, volumes, b.CommonBuildOpts.Volumes, b.CommonBuildOpts.ShmSize, namespaceOptions, options.Secrets, options.RunMounts)
|
||||
runArtifacts, err := b.setupMounts(mountPoint, spec, path, options.Mounts, bindFiles, volumes, b.CommonBuildOpts.Volumes, b.CommonBuildOpts.ShmSize, namespaceOptions, options.Secrets, options.SSHSources, options.RunMounts)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error resolving mountpoints for container %q", b.ContainerID)
|
||||
}
|
||||
if runArtifacts.SSHAuthSock != "" {
|
||||
sshenv := "SSH_AUTH_SOCK=" + runArtifacts.SSHAuthSock
|
||||
spec.Process.Env = append(spec.Process.Env, sshenv)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := cleanupRunMounts(runMountTargets, mountPoint); err != nil {
|
||||
if err := cleanupRunMounts(mountPoint, runArtifacts); err != nil {
|
||||
options.Logger.Errorf("unabe to cleanup run mounts %v", err)
|
||||
}
|
||||
}()
|
||||
@@ -409,7 +413,7 @@ func runSetupBuiltinVolumes(mountLabel, mountPoint, containerDir string, builtin
|
||||
return mounts, nil
|
||||
}
|
||||
|
||||
func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath string, optionMounts []specs.Mount, bindFiles map[string]string, builtinVolumes, volumeMounts []string, shmSize string, namespaceOptions define.NamespaceOptions, secrets map[string]string, runFileMounts []string) (runMountTargets []string, err error) {
|
||||
func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath string, optionMounts []specs.Mount, bindFiles map[string]string, builtinVolumes, volumeMounts []string, shmSize string, namespaceOptions define.NamespaceOptions, secrets map[string]string, sshSources map[string]*sshagent.Source, runFileMounts []string) (*runMountArtifacts, error) {
|
||||
// Start building a new list of mounts.
|
||||
var mounts []specs.Mount
|
||||
haveMount := func(destination string) bool {
|
||||
@@ -517,18 +521,17 @@ func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath st
|
||||
subscriptionMounts := subscriptions.MountsWithUIDGID(b.MountLabel, cdir, b.DefaultMountsFilePath, mountPoint, int(rootUID), int(rootGID), unshare.IsRootless(), false)
|
||||
|
||||
// Get the list of mounts that are just for this Run() call.
|
||||
runMounts, runTargets, err := runSetupRunMounts(runFileMounts, secrets, b.MountLabel, cdir, spec.Linux.UIDMappings, spec.Linux.GIDMappings)
|
||||
// TODO: acui: de-spaghettify run mounts
|
||||
runMounts, mountArtifacts, err := runSetupRunMounts(runFileMounts, secrets, sshSources, b.MountLabel, cdir, spec.Linux.UIDMappings, spec.Linux.GIDMappings, b.ProcessLabel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Add temporary copies of the contents of volume locations at the
|
||||
// volume locations, unless we already have something there.
|
||||
builtins, err := runSetupBuiltinVolumes(b.MountLabel, mountPoint, cdir, builtinVolumes, int(rootUID), int(rootGID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get host UID and GID of the container process.
|
||||
processUID, processGID, err := util.GetHostIDs(spec.Linux.UIDMappings, spec.Linux.GIDMappings, spec.Process.User.UID, spec.Process.User.GID)
|
||||
if err != nil {
|
||||
@@ -554,22 +557,55 @@ func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath st
|
||||
|
||||
// Set the list in the spec.
|
||||
spec.Mounts = mounts
|
||||
return runTargets, nil
|
||||
return mountArtifacts, nil
|
||||
}
|
||||
|
||||
// addNetworkConfig copies files from host and sets them up to bind mount into container
|
||||
func (b *Builder) addNetworkConfig(rdir, hostPath string, chownOpts *idtools.IDPair, dnsServers, dnsSearch, dnsOptions []string, namespaceOptions define.NamespaceOptions) (string, error) {
|
||||
stat, err := os.Stat(hostPath)
|
||||
// addResolvConf copies files from host and sets them up to bind mount into container
|
||||
func (b *Builder) addResolvConf(rdir string, chownOpts *idtools.IDPair, dnsServers, dnsSearch, dnsOptions []string, namespaceOptions define.NamespaceOptions) (string, error) {
|
||||
resolvConf := "/etc/resolv.conf"
|
||||
|
||||
stat, err := os.Stat(resolvConf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
contents, err := ioutil.ReadFile(hostPath)
|
||||
if err != nil {
|
||||
contents, err := ioutil.ReadFile(resolvConf)
|
||||
// resolv.conf doesn't have to exists
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
netns := false
|
||||
ns := namespaceOptions.Find(string(spec.NetworkNamespace))
|
||||
if ns != nil && !ns.Host {
|
||||
netns = true
|
||||
}
|
||||
|
||||
nameservers := resolvconf.GetNameservers(contents, types.IPv4)
|
||||
// check if systemd-resolved is used, assume it is used when 127.0.0.53 is the only nameserver
|
||||
if len(nameservers) == 1 && nameservers[0] == "127.0.0.53" && netns {
|
||||
// read the actual resolv.conf file for systemd-resolved
|
||||
resolvedContents, err := ioutil.ReadFile("/run/systemd/resolve/resolv.conf")
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return "", errors.Wrapf(err, "detected that systemd-resolved is in use, but could not locate real resolv.conf")
|
||||
}
|
||||
} else {
|
||||
contents = resolvedContents
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the container's /etc/resolv.conf is compatible with its
|
||||
// network configuration.
|
||||
if netns {
|
||||
// FIXME handle IPv6
|
||||
resolve, err := resolvconf.FilterResolvDNS(contents, true)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "error parsing host resolv.conf")
|
||||
}
|
||||
contents = resolve.Content
|
||||
}
|
||||
search := resolvconf.GetSearchDomains(contents)
|
||||
nameservers := resolvconf.GetNameservers(contents, types.IP)
|
||||
nameservers = resolvconf.GetNameservers(contents, types.IP)
|
||||
options := resolvconf.GetOptions(contents)
|
||||
|
||||
defaultContainerConfig, err := config.Default()
|
||||
@@ -582,7 +618,6 @@ func (b *Builder) addNetworkConfig(rdir, hostPath string, chownOpts *idtools.IDP
|
||||
}
|
||||
|
||||
if b.Isolation == IsolationOCIRootless {
|
||||
ns := namespaceOptions.Find(string(specs.NetworkNamespace))
|
||||
if ns != nil && !ns.Host && ns.Path == "" {
|
||||
// if we are using slirp4netns, also add the built-in DNS server.
|
||||
logrus.Debugf("adding slirp4netns 10.0.2.3 built-in DNS server")
|
||||
@@ -607,7 +642,7 @@ func (b *Builder) addNetworkConfig(rdir, hostPath string, chownOpts *idtools.IDP
|
||||
options = dnsOptions
|
||||
}
|
||||
|
||||
cfile := filepath.Join(rdir, filepath.Base(hostPath))
|
||||
cfile := filepath.Join(rdir, filepath.Base(resolvConf))
|
||||
if _, err = resolvconf.Build(cfile, nameservers, search, options); err != nil {
|
||||
return "", errors.Wrapf(err, "error building resolv.conf for container %s", b.ContainerID)
|
||||
}
|
||||
@@ -702,6 +737,10 @@ func setupTerminal(g *generate.Generator, terminalPolicy TerminalPolicy, termina
|
||||
}
|
||||
|
||||
func runUsingRuntime(isolation define.Isolation, options RunOptions, configureNetwork bool, configureNetworks, moreCreateArgs []string, spec *specs.Spec, bundlePath, containerName string) (wstatus unix.WaitStatus, err error) {
|
||||
if options.Logger == nil {
|
||||
options.Logger = logrus.StandardLogger()
|
||||
}
|
||||
|
||||
// Lock the caller to a single OS-level thread.
|
||||
runtime.LockOSThread()
|
||||
|
||||
@@ -1743,7 +1782,6 @@ func (b *Builder) cleanupTempVolumes() {
|
||||
}
|
||||
|
||||
func (b *Builder) runSetupVolumeMounts(mountLabel string, volumeMounts []string, optionMounts []specs.Mount, rootUID, rootGID, processUID, processGID int) (mounts []specs.Mount, Err error) {
|
||||
|
||||
// Make sure the overlay directory is clean before running
|
||||
containerDir, err := b.store.ContainerDirectory(b.ContainerID)
|
||||
if err != nil {
|
||||
@@ -1805,7 +1843,6 @@ func (b *Builder) runSetupVolumeMounts(mountLabel string, volumeMounts []string,
|
||||
|
||||
overlayMount, err := overlay.Mount(contentDir, host, container, rootUID, rootGID, b.store.GraphOptions())
|
||||
if err == nil {
|
||||
|
||||
b.TempVolumes[contentDir] = true
|
||||
}
|
||||
|
||||
@@ -2287,21 +2324,23 @@ func init() {
|
||||
}
|
||||
|
||||
// runSetupRunMounts sets up mounts that exist only in this RUN, not in subsequent runs
|
||||
func runSetupRunMounts(mounts []string, secrets map[string]string, mountlabel string, containerWorkingDir string, uidmap []spec.LinuxIDMapping, gidmap []spec.LinuxIDMapping) ([]spec.Mount, []string, error) {
|
||||
func runSetupRunMounts(mounts []string, secrets map[string]string, sshSources map[string]*sshagent.Source, mountlabel string, containerWorkingDir string, uidmap []spec.LinuxIDMapping, gidmap []spec.LinuxIDMapping, processLabel string) ([]spec.Mount, *runMountArtifacts, error) {
|
||||
mountTargets := make([]string, 0, 10)
|
||||
finalMounts := make([]specs.Mount, 0, len(mounts))
|
||||
agents := make([]*sshagent.AgentServer, 0, len(mounts))
|
||||
sshCount := 0
|
||||
defaultSSHSock := ""
|
||||
tokens := []string{}
|
||||
for _, mount := range mounts {
|
||||
arr := strings.SplitN(mount, ",", 2)
|
||||
if len(arr) < 2 {
|
||||
return nil, nil, errors.New("invalid mount syntax")
|
||||
}
|
||||
|
||||
kv := strings.Split(arr[0], "=")
|
||||
if len(kv) != 2 || kv[0] != "type" {
|
||||
return nil, nil, errors.New("invalid mount type")
|
||||
}
|
||||
|
||||
tokens := strings.Split(arr[1], ",")
|
||||
if len(arr) == 2 {
|
||||
tokens = strings.Split(arr[1], ",")
|
||||
}
|
||||
// For now, we only support type secret.
|
||||
switch kv[1] {
|
||||
case "secret":
|
||||
@@ -2314,16 +2353,38 @@ func runSetupRunMounts(mounts []string, secrets map[string]string, mountlabel st
|
||||
mountTargets = append(mountTargets, mount.Destination)
|
||||
|
||||
}
|
||||
case "ssh":
|
||||
mount, agent, err := getSSHMount(tokens, sshCount, sshSources, mountlabel, uidmap, gidmap, processLabel)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if mount != nil {
|
||||
finalMounts = append(finalMounts, *mount)
|
||||
mountTargets = append(mountTargets, mount.Destination)
|
||||
agents = append(agents, agent)
|
||||
if sshCount == 0 {
|
||||
defaultSSHSock = mount.Destination
|
||||
}
|
||||
// Count is needed as the default destination of the ssh sock inside the container is /run/buildkit/ssh_agent.{i}
|
||||
sshCount++
|
||||
}
|
||||
default:
|
||||
return nil, nil, errors.Errorf("invalid filesystem type %q", kv[1])
|
||||
return nil, nil, errors.Errorf("invalid mount type %q", kv[1])
|
||||
}
|
||||
}
|
||||
return finalMounts, mountTargets, nil
|
||||
artifacts := &runMountArtifacts{
|
||||
RunMountTargets: mountTargets,
|
||||
Agents: agents,
|
||||
SSHAuthSock: defaultSSHSock,
|
||||
}
|
||||
return finalMounts, artifacts, nil
|
||||
}
|
||||
|
||||
func getSecretMount(tokens []string, secrets map[string]string, mountlabel string, containerWorkingDir string, uidmap []spec.LinuxIDMapping, gidmap []spec.LinuxIDMapping) (*spec.Mount, error) {
|
||||
errInvalidSyntax := errors.New("secret should have syntax id=id[,target=path,required=bool,mode=uint,uid=uint,gid=uint")
|
||||
|
||||
if len(tokens) == 0 {
|
||||
return nil, errInvalidSyntax
|
||||
}
|
||||
var err error
|
||||
var id, target string
|
||||
var required bool
|
||||
@@ -2419,11 +2480,134 @@ func getSecretMount(tokens []string, secrets map[string]string, mountlabel strin
|
||||
return &newMount, nil
|
||||
}
|
||||
|
||||
func cleanupRunMounts(paths []string, mountpoint string) error {
|
||||
// getSSHMount parses the --mount type=ssh flag in the Containerfile, checks if there's an ssh source provided, and creates and starts an ssh-agent to be forwarded into the container
|
||||
func getSSHMount(tokens []string, count int, sshsources map[string]*sshagent.Source, mountlabel string, uidmap []spec.LinuxIDMapping, gidmap []spec.LinuxIDMapping, processLabel string) (*spec.Mount, *sshagent.AgentServer, error) {
|
||||
errInvalidSyntax := errors.New("ssh should have syntax id=id[,target=path,required=bool,mode=uint,uid=uint,gid=uint")
|
||||
|
||||
var err error
|
||||
var id, target string
|
||||
var required bool
|
||||
var uid, gid uint32
|
||||
var mode uint32 = 400
|
||||
for _, val := range tokens {
|
||||
kv := strings.SplitN(val, "=", 2)
|
||||
if len(kv) < 2 {
|
||||
return nil, nil, errInvalidSyntax
|
||||
}
|
||||
switch kv[0] {
|
||||
case "id":
|
||||
id = kv[1]
|
||||
case "target", "dst", "destination":
|
||||
target = kv[1]
|
||||
case "required":
|
||||
required, err = strconv.ParseBool(kv[1])
|
||||
if err != nil {
|
||||
return nil, nil, errInvalidSyntax
|
||||
}
|
||||
case "mode":
|
||||
mode64, err := strconv.ParseUint(kv[1], 8, 32)
|
||||
if err != nil {
|
||||
return nil, nil, errInvalidSyntax
|
||||
}
|
||||
mode = uint32(mode64)
|
||||
case "uid":
|
||||
uid64, err := strconv.ParseUint(kv[1], 10, 32)
|
||||
if err != nil {
|
||||
return nil, nil, errInvalidSyntax
|
||||
}
|
||||
uid = uint32(uid64)
|
||||
case "gid":
|
||||
gid64, err := strconv.ParseUint(kv[1], 10, 32)
|
||||
if err != nil {
|
||||
return nil, nil, errInvalidSyntax
|
||||
}
|
||||
gid = uint32(gid64)
|
||||
default:
|
||||
return nil, nil, errInvalidSyntax
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if id == "" {
|
||||
id = "default"
|
||||
}
|
||||
// Default location for secretis is /run/buildkit/ssh_agent.{i}
|
||||
if target == "" {
|
||||
target = fmt.Sprintf("/run/buildkit/ssh_agent.%d", count)
|
||||
}
|
||||
|
||||
sshsource, ok := sshsources[id]
|
||||
if !ok {
|
||||
if required {
|
||||
return nil, nil, errors.Errorf("ssh required but no ssh with id %s found", id)
|
||||
}
|
||||
return nil, nil, nil
|
||||
}
|
||||
// Create new agent from keys or socket
|
||||
fwdAgent, err := sshagent.NewAgentServer(sshsource)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Start ssh server, and get the host sock we're mounting in the container
|
||||
hostSock, err := fwdAgent.Serve(processLabel)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if err := label.Relabel(filepath.Dir(hostSock), mountlabel, false); err != nil {
|
||||
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
|
||||
logrus.Errorf("error shutting down agent: %v", shutdownErr)
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := label.Relabel(hostSock, mountlabel, false); err != nil {
|
||||
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
|
||||
logrus.Errorf("error shutting down agent: %v", shutdownErr)
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
hostUID, hostGID, err := util.GetHostIDs(uidmap, gidmap, uid, gid)
|
||||
if err != nil {
|
||||
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
|
||||
logrus.Errorf("error shutting down agent: %v", shutdownErr)
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := os.Lchown(hostSock, int(hostUID), int(hostGID)); err != nil {
|
||||
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
|
||||
logrus.Errorf("error shutting down agent: %v", shutdownErr)
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := os.Chmod(hostSock, os.FileMode(mode)); err != nil {
|
||||
if shutdownErr := fwdAgent.Shutdown(); shutdownErr != nil {
|
||||
logrus.Errorf("error shutting down agent: %v", shutdownErr)
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
newMount := specs.Mount{
|
||||
Destination: target,
|
||||
Type: "bind",
|
||||
Source: hostSock,
|
||||
Options: []string{"bind", "rprivate", "ro"},
|
||||
}
|
||||
return &newMount, fwdAgent, nil
|
||||
}
|
||||
|
||||
// cleanupRunMounts cleans up run mounts so they only appear in this run.
|
||||
func cleanupRunMounts(mountpoint string, artifacts *runMountArtifacts) error {
|
||||
for _, agent := range artifacts.Agents {
|
||||
err := agent.Shutdown()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
opts := copier.RemoveOptions{
|
||||
All: true,
|
||||
}
|
||||
for _, path := range paths {
|
||||
for _, path := range artifacts.RunMountTargets {
|
||||
err := copier.Remove(mountpoint, path, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user