Skip to content

Commit

Permalink
Merge pull request kubernetes-sigs#1302 from amwat/podman2
Browse files Browse the repository at this point in the history
Enable basic podman support.
  • Loading branch information
k8s-ci-robot authored Feb 1, 2020
2 parents 1516392 + fc098e2 commit 2cf2a29
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 30 deletions.
5 changes: 4 additions & 1 deletion pkg/cluster/internal/providers/podman/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ func ensureNodeImages(logger log.Logger, status *cli.Status, cfg *config.Cluster
// prints user friendly message
friendlyImageName := image
if strings.Contains(image, "@sha256:") {
friendlyImageName = strings.Split(image, "@sha256:")[0]
splits := strings.Split(image, "@sha256:")
friendlyImageName = splits[0]
// possibly trim tag and use sha
image = strings.Split(friendlyImageName, ":")[0] + "@sha256:" + splits[1]
}
status.Start(fmt.Sprintf("Ensuring node image (%s) 🖼", friendlyImageName))
if _, err := pullIfNotPresent(logger, image, 4); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/cluster/internal/providers/podman/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (n *node) Role() (string, error) {
func (n *node) IP() (ipv4 string, ipv6 string, err error) {
// retrieve the IP address of the node using podman inspect
cmd := exec.Command("podman", "inspect",
"-f", "{{range .NetworkSettings.Networks}}{{.IPAddress}},{{.GlobalIPv6Address}}{{end}}",
"-f", "{{.NetworkSettings.IPAddress}},{{.NetworkSettings.GlobalIPv6Address}}",
n.name, // ... against the "node" container
)
lines, err := exec.CombinedOutputLines(cmd)
Expand Down
39 changes: 30 additions & 9 deletions pkg/cluster/internal/providers/podman/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,23 @@ limitations under the License.
package podman

import (
"encoding/json"
"fmt"
"net"
"os"
"strconv"
"strings"

"k8s.io/apimachinery/pkg/util/sets"

"sigs.k8s.io/kind/pkg/cluster/nodes"
"sigs.k8s.io/kind/pkg/cluster/nodeutils"
"sigs.k8s.io/kind/pkg/errors"
"sigs.k8s.io/kind/pkg/exec"
"sigs.k8s.io/kind/pkg/log"

"sigs.k8s.io/kind/pkg/cluster/internal/providers/provider"
"sigs.k8s.io/kind/pkg/cluster/internal/providers/provider/common"
"sigs.k8s.io/kind/pkg/cluster/nodeutils"
"sigs.k8s.io/kind/pkg/internal/apis/config"
"sigs.k8s.io/kind/pkg/internal/cli"
)
Expand All @@ -54,6 +57,11 @@ func (p *Provider) Provision(status *cli.Status, cluster string, cfg *config.Clu
return err
}

// kind doesn't currently work with podman rootless, surface a warning
if os.Geteuid() != 0 {
p.logger.Warn("podman provider may not work properly in rootless mode")
}

// TODO: validate cfg
// ensure node images are pulled before actually provisioning
if err := ensureNodeImages(p.logger, status, cfg); err != nil {
Expand Down Expand Up @@ -152,9 +160,8 @@ func (p *Provider) GetAPIServerEndpoint(cluster string) (string, error) {
// retrieve the specific port mapping using podman inspect
cmd := exec.Command(
"podman", "inspect",
"--format", fmt.Sprintf(
"{{ with (index (index .NetworkSettings.Ports \"%d/tcp\") 0) }}{{ printf \"%%s\t%%s\" .HostIp .HostPort }}{{ end }}", common.APIServerInternalPort,
),
"--format",
"{{ json .NetworkSettings.Ports }}",
n.String(),
)
lines, err := exec.OutputLines(cmd)
Expand All @@ -164,13 +171,27 @@ func (p *Provider) GetAPIServerEndpoint(cluster string) (string, error) {
if len(lines) != 1 {
return "", errors.Errorf("network details should only be one line, got %d lines", len(lines))
}
parts := strings.Split(lines[0], "\t")
if len(parts) != 2 {
return "", errors.Errorf("network details should only be two parts, got %d", len(parts))

// portMapping maps to the standard CNI portmapping capability
// see: https://github.com/containernetworking/cni/blob/spec-v0.4.0/CONVENTIONS.md
type portMapping struct {
HostPort int32 `json:"hostPort"`
ContainerPort int32 `json:"containerPort"`
Protocol string `json:"protocol"`
HostIP string `json:"hostIP"`
}

var portMappings []portMapping
if err := json.Unmarshal([]byte(lines[0]), &portMappings); err != nil {
return "", errors.Errorf("invalid network details: %v", err)
}
for _, pm := range portMappings {
if pm.ContainerPort == common.APIServerInternalPort && pm.Protocol == "tcp" {
return net.JoinHostPort(pm.HostIP, strconv.Itoa(int(pm.HostPort))), nil
}
}

// join host and port
return net.JoinHostPort(parts[0], parts[1]), nil
return "", errors.Errorf("unable to find apiserver endpoint information")
}

// node returns a new node handle for this provider
Expand Down
9 changes: 5 additions & 4 deletions pkg/cluster/internal/providers/podman/provision.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,6 @@ func commonArgs(cluster string, cfg *config.Cluster) ([]string, error) {
args = append(args, "-e", fmt.Sprintf("%s=%s", key, val))
}

// handle hosts that have user namespace remapping enabled
if usernsRemap() {
args = append(args, "--userns=host")
}
return args, nil
}

Expand Down Expand Up @@ -307,6 +303,11 @@ func generatePortMappings(clusterIPFamily config.ClusterIPFamily, portMappings .
// generate the actual mapping arg
protocol := string(pm.Protocol)
hostPortBinding := net.JoinHostPort(pm.ListenAddress, fmt.Sprintf("%d", pm.HostPort))
// Podman expects empty string instead of 0 to assign a random port
// https://github.com/containers/libpod/blob/master/pkg/spec/ports.go#L68-L69
if strings.HasSuffix(hostPortBinding, ":0") {
hostPortBinding = strings.TrimSuffix(hostPortBinding, "0")
}
args = append(args, fmt.Sprintf("--publish=%s:%d/%s", hostPortBinding, pm.ContainerPort, protocol))
}
return args
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,6 @@ import (
"sigs.k8s.io/kind/pkg/exec"
)

// usernsRemap checks if userns-remap is enabled in podmand
func usernsRemap() bool {
cmd := exec.Command("podman", "info", "--format", "'{{json .SecurityOptions}}'")
lines, err := exec.CombinedOutputLines(cmd)
if err != nil {
return false
}
if len(lines) > 0 {
if strings.Contains(lines[0], "name=userns") {
return true
}
}
return false
}

func getPodmanVersion() (*version.Version, error) {
cmd := exec.Command("podman", "--version")
lines, err := exec.CombinedOutputLines(cmd)
Expand Down

0 comments on commit 2cf2a29

Please sign in to comment.