Add podman-env for connecting with podman-remote (#6351)
* Refactor: add the docker vars after the shell vars * Move shell handling functions to separate package * Rename env source file to docker-env like command * Add podman-env for connecting with podman-remote * Remove leading Shell prefix from the shell package * Add some documentation describing podman service * Address some podman-env issues pointed out by lintpull/6582/head
parent
a283fd695a
commit
ff763db1e7
|
@ -26,10 +26,8 @@ import (
|
|||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/docker/machine/libmachine/drivers"
|
||||
"github.com/docker/machine/libmachine/shell"
|
||||
"github.com/docker/machine/libmachine/state"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -44,71 +42,25 @@ import (
|
|||
"k8s.io/minikube/pkg/minikube/localpath"
|
||||
"k8s.io/minikube/pkg/minikube/machine"
|
||||
"k8s.io/minikube/pkg/minikube/out"
|
||||
"k8s.io/minikube/pkg/minikube/shell"
|
||||
)
|
||||
|
||||
var envTmpl = fmt.Sprintf("{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerTLSVerify }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerHost }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerCertPath }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .MinikubeDockerdProfile }}{{ .Suffix }}{{ if .NoProxyVar }}{{ .Prefix }}{{ .NoProxyVar }}{{ .Delimiter }}{{ .NoProxyValue }}{{ .Suffix }}{{end}}{{ .UsageHint }}", constants.DockerTLSVerifyEnv, constants.DockerHostEnv, constants.DockerCertPathEnv, constants.MinikubeActiveDockerdEnv)
|
||||
var dockerEnvTmpl = fmt.Sprintf("{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerTLSVerify }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerHost }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerCertPath }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .MinikubeDockerdProfile }}{{ .Suffix }}{{ if .NoProxyVar }}{{ .Prefix }}{{ .NoProxyVar }}{{ .Delimiter }}{{ .NoProxyValue }}{{ .Suffix }}{{end}}{{ .UsageHint }}", constants.DockerTLSVerifyEnv, constants.DockerHostEnv, constants.DockerCertPathEnv, constants.MinikubeActiveDockerdEnv)
|
||||
|
||||
const (
|
||||
fishSetPfx = "set -gx "
|
||||
fishSetSfx = "\"\n"
|
||||
fishSetDelim = " \""
|
||||
|
||||
fishUnsetPfx = "set -e "
|
||||
fishUnsetSfx = "\n"
|
||||
|
||||
psSetPfx = "$Env:"
|
||||
psSetSfx = "\"\n"
|
||||
psSetDelim = " = \""
|
||||
|
||||
psUnsetPfx = `Remove-Item Env:\\`
|
||||
psUnsetSfx = "\n"
|
||||
|
||||
cmdSetPfx = "SET "
|
||||
cmdSetSfx = "\n"
|
||||
cmdSetDelim = "="
|
||||
|
||||
cmdUnsetPfx = "SET "
|
||||
cmdUnsetSfx = "\n"
|
||||
cmdUnsetDelim = "="
|
||||
|
||||
emacsSetPfx = "(setenv \""
|
||||
emacsSetSfx = "\")\n"
|
||||
emacsSetDelim = "\" \""
|
||||
|
||||
emacsUnsetPfx = "(setenv \""
|
||||
emacsUnsetSfx = ")\n"
|
||||
emacsUnsetDelim = "\" nil"
|
||||
|
||||
bashSetPfx = "export "
|
||||
bashSetSfx = "\"\n"
|
||||
bashSetDelim = "=\""
|
||||
|
||||
bashUnsetPfx = "unset "
|
||||
bashUnsetSfx = "\n"
|
||||
|
||||
nonePfx = ""
|
||||
noneSfx = "\n"
|
||||
noneDelim = "="
|
||||
)
|
||||
|
||||
// ShellConfig represents the shell config
|
||||
type ShellConfig struct {
|
||||
Prefix string
|
||||
Delimiter string
|
||||
Suffix string
|
||||
// DockerShellConfig represents the shell config for Docker
|
||||
type DockerShellConfig struct {
|
||||
shell.Config
|
||||
DockerCertPath string
|
||||
DockerHost string
|
||||
DockerTLSVerify string
|
||||
MinikubeDockerdProfile string
|
||||
UsageHint string
|
||||
NoProxyVar string
|
||||
NoProxyValue string
|
||||
}
|
||||
|
||||
var (
|
||||
noProxy bool
|
||||
forceShell string
|
||||
unset bool
|
||||
dockerUnset bool
|
||||
defaultNoProxyGetter NoProxyGetter
|
||||
)
|
||||
|
||||
|
@ -120,45 +72,18 @@ type NoProxyGetter interface {
|
|||
// EnvNoProxyGetter gets the no_proxy variable, using environment
|
||||
type EnvNoProxyGetter struct{}
|
||||
|
||||
func generateUsageHint(profile, sh string) string {
|
||||
// dockerShellCfgSet generates context variables for "docker-env"
|
||||
func dockerShellCfgSet(ec DockerEnvConfig, envMap map[string]string) *DockerShellConfig {
|
||||
profile := ec.profile
|
||||
const usgPlz = "To point your shell to minikube's docker-daemon, run:"
|
||||
var usgCmd = fmt.Sprintf("minikube -p %s docker-env", profile)
|
||||
var usageHintMap = map[string]string{
|
||||
"bash": fmt.Sprintf(`
|
||||
# %s
|
||||
# eval $(%s)
|
||||
`, usgPlz, usgCmd),
|
||||
"fish": fmt.Sprintf(`
|
||||
# %s
|
||||
# eval (%s)
|
||||
`, usgPlz, usgCmd),
|
||||
"powershell": fmt.Sprintf(`# %s
|
||||
# & %s | Invoke-Expression
|
||||
`, usgPlz, usgCmd),
|
||||
"cmd": fmt.Sprintf(`REM %s
|
||||
REM @FOR /f "tokens=*" %%i IN ('%s') DO @%%i
|
||||
`, usgPlz, usgCmd),
|
||||
"emacs": fmt.Sprintf(`;; %s
|
||||
;; (with-temp-buffer (shell-command "%s" (current-buffer)) (eval-buffer))
|
||||
`, usgPlz, usgCmd),
|
||||
}
|
||||
|
||||
hint, ok := usageHintMap[sh]
|
||||
if !ok {
|
||||
return usageHintMap["bash"]
|
||||
}
|
||||
return hint
|
||||
}
|
||||
|
||||
// shellCfgSet generates context variables for "docker-env"
|
||||
func shellCfgSet(ec EnvConfig, envMap map[string]string) *ShellConfig {
|
||||
s := &ShellConfig{
|
||||
DockerCertPath: envMap[constants.DockerCertPathEnv],
|
||||
DockerHost: envMap[constants.DockerHostEnv],
|
||||
DockerTLSVerify: envMap[constants.DockerTLSVerifyEnv],
|
||||
MinikubeDockerdProfile: envMap[constants.MinikubeActiveDockerdEnv],
|
||||
UsageHint: generateUsageHint(ec.profile, ec.shell),
|
||||
s := &DockerShellConfig{
|
||||
Config: *shell.CfgSet(ec.EnvConfig, usgPlz, usgCmd),
|
||||
}
|
||||
s.DockerCertPath = envMap[constants.DockerCertPathEnv]
|
||||
s.DockerHost = envMap[constants.DockerHostEnv]
|
||||
s.DockerTLSVerify = envMap[constants.DockerTLSVerifyEnv]
|
||||
s.MinikubeDockerdProfile = envMap[constants.MinikubeActiveDockerdEnv]
|
||||
|
||||
if ec.noProxy {
|
||||
noProxyVar, noProxyValue := defaultNoProxyGetter.GetNoProxyVar()
|
||||
|
@ -177,33 +102,6 @@ func shellCfgSet(ec EnvConfig, envMap map[string]string) *ShellConfig {
|
|||
s.NoProxyValue = noProxyValue
|
||||
}
|
||||
|
||||
switch ec.shell {
|
||||
case "fish":
|
||||
s.Prefix = fishSetPfx
|
||||
s.Suffix = fishSetSfx
|
||||
s.Delimiter = fishSetDelim
|
||||
case "powershell":
|
||||
s.Prefix = psSetPfx
|
||||
s.Suffix = psSetSfx
|
||||
s.Delimiter = psSetDelim
|
||||
case "cmd":
|
||||
s.Prefix = cmdSetPfx
|
||||
s.Suffix = cmdSetSfx
|
||||
s.Delimiter = cmdSetDelim
|
||||
case "emacs":
|
||||
s.Prefix = emacsSetPfx
|
||||
s.Suffix = emacsSetSfx
|
||||
s.Delimiter = emacsSetDelim
|
||||
case "none":
|
||||
s.Prefix = nonePfx
|
||||
s.Suffix = noneSfx
|
||||
s.Delimiter = noneDelim
|
||||
s.UsageHint = ""
|
||||
default:
|
||||
s.Prefix = bashSetPfx
|
||||
s.Suffix = bashSetSfx
|
||||
s.Delimiter = bashSetDelim
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
|
@ -236,7 +134,7 @@ func isDockerActive(d drivers.Driver) (bool, error) {
|
|||
return err == nil && s == "active", nil
|
||||
}
|
||||
|
||||
// envCmd represents the docker-env command
|
||||
// dockerEnvCmd represents the docker-env command
|
||||
var dockerEnvCmd = &cobra.Command{
|
||||
Use: "docker-env",
|
||||
Short: "Sets up docker env variables; similar to '$(docker-machine env)'",
|
||||
|
@ -282,57 +180,59 @@ var dockerEnvCmd = &cobra.Command{
|
|||
exit.WithError("Error getting host IP", err)
|
||||
}
|
||||
|
||||
ec := EnvConfig{
|
||||
profile: profile,
|
||||
driver: host.DriverName,
|
||||
shell: forceShell,
|
||||
hostIP: hostIP,
|
||||
certsDir: localpath.MakeMiniPath("certs"),
|
||||
noProxy: noProxy,
|
||||
sh := shell.EnvConfig{
|
||||
Shell: shell.ForceShell,
|
||||
}
|
||||
ec := DockerEnvConfig{
|
||||
EnvConfig: sh,
|
||||
profile: profile,
|
||||
driver: host.DriverName,
|
||||
hostIP: hostIP,
|
||||
certsDir: localpath.MakeMiniPath("certs"),
|
||||
noProxy: noProxy,
|
||||
}
|
||||
|
||||
if ec.shell == "" {
|
||||
ec.shell, err = shell.Detect()
|
||||
if ec.Shell == "" {
|
||||
ec.Shell, err = shell.Detect()
|
||||
if err != nil {
|
||||
exit.WithError("Error detecting shell", err)
|
||||
}
|
||||
}
|
||||
|
||||
if unset {
|
||||
if err := unsetScript(ec, os.Stdout); err != nil {
|
||||
if dockerUnset {
|
||||
if err := dockerUnsetScript(ec, os.Stdout); err != nil {
|
||||
exit.WithError("Error generating unset output", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := setScript(ec, os.Stdout); err != nil {
|
||||
if err := dockerSetScript(ec, os.Stdout); err != nil {
|
||||
exit.WithError("Error generating set output", err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// EnvConfig encapsulates all external inputs into shell generation
|
||||
type EnvConfig struct {
|
||||
// DockerEnvConfig encapsulates all external inputs into shell generation for Docker
|
||||
type DockerEnvConfig struct {
|
||||
shell.EnvConfig
|
||||
profile string
|
||||
shell string
|
||||
driver string
|
||||
hostIP string
|
||||
certsDir string
|
||||
noProxy bool
|
||||
}
|
||||
|
||||
// setScript writes out a shell-compatible 'docker-env' script
|
||||
func setScript(ec EnvConfig, w io.Writer) error {
|
||||
tmpl := template.Must(template.New("envConfig").Parse(envTmpl))
|
||||
// dockerSetScript writes out a shell-compatible 'docker-env' script
|
||||
func dockerSetScript(ec DockerEnvConfig, w io.Writer) error {
|
||||
envVars, err := dockerEnvVars(ec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tmpl.Execute(w, shellCfgSet(ec, envVars))
|
||||
return shell.SetScript(ec.EnvConfig, w, dockerEnvTmpl, dockerShellCfgSet(ec, envVars))
|
||||
}
|
||||
|
||||
// setScript writes out a shell-compatible 'docker-env unset' script
|
||||
func unsetScript(ec EnvConfig, w io.Writer) error {
|
||||
// dockerSetScript writes out a shell-compatible 'docker-env unset' script
|
||||
func dockerUnsetScript(ec DockerEnvConfig, w io.Writer) error {
|
||||
vars := []string{
|
||||
constants.DockerTLSVerifyEnv,
|
||||
constants.DockerHostEnv,
|
||||
|
@ -347,29 +247,7 @@ func unsetScript(ec EnvConfig, w io.Writer) error {
|
|||
}
|
||||
}
|
||||
|
||||
var sb strings.Builder
|
||||
switch ec.shell {
|
||||
case "fish":
|
||||
for _, v := range vars {
|
||||
sb.WriteString(fmt.Sprintf("%s%s%s", fishUnsetPfx, v, fishUnsetSfx))
|
||||
}
|
||||
case "powershell":
|
||||
sb.WriteString(fmt.Sprintf("%s%s%s", psUnsetPfx, strings.Join(vars, " Env:\\\\"), psUnsetSfx))
|
||||
case "cmd":
|
||||
for _, v := range vars {
|
||||
sb.WriteString(fmt.Sprintf("%s%s%s%s", cmdUnsetPfx, v, cmdUnsetDelim, cmdUnsetSfx))
|
||||
}
|
||||
case "emacs":
|
||||
for _, v := range vars {
|
||||
sb.WriteString(fmt.Sprintf("%s%s%s%s", emacsUnsetPfx, v, emacsUnsetDelim, emacsUnsetSfx))
|
||||
}
|
||||
case "none":
|
||||
sb.WriteString(fmt.Sprintf("%s%s%s", nonePfx, strings.Join(vars, " "), noneSfx))
|
||||
default:
|
||||
sb.WriteString(fmt.Sprintf("%s%s%s", bashUnsetPfx, strings.Join(vars, " "), bashUnsetSfx))
|
||||
}
|
||||
_, err := w.Write([]byte(sb.String()))
|
||||
return err
|
||||
return shell.UnsetScript(ec.EnvConfig, w, vars)
|
||||
}
|
||||
|
||||
// dockerURL returns a the docker endpoint URL for an ip/port pair.
|
||||
|
@ -378,7 +256,7 @@ func dockerURL(ip string, port int) string {
|
|||
}
|
||||
|
||||
// dockerEnvVars gets the necessary docker env variables to allow the use of minikube's docker daemon
|
||||
func dockerEnvVars(ec EnvConfig) (map[string]string, error) {
|
||||
func dockerEnvVars(ec DockerEnvConfig) (map[string]string, error) {
|
||||
env := map[string]string{
|
||||
constants.DockerTLSVerifyEnv: "1",
|
||||
constants.DockerHostEnv: dockerURL(ec.hostIP, constants.DockerDaemonPort),
|
||||
|
@ -399,6 +277,6 @@ func dockerEnvVars(ec EnvConfig) (map[string]string, error) {
|
|||
func init() {
|
||||
defaultNoProxyGetter = &EnvNoProxyGetter{}
|
||||
dockerEnvCmd.Flags().BoolVar(&noProxy, "no-proxy", false, "Add machine IP to NO_PROXY environment variable")
|
||||
dockerEnvCmd.Flags().StringVar(&forceShell, "shell", "", "Force environment to be configured for a specified shell: [fish, cmd, powershell, tcsh, bash, zsh], default is auto-detect")
|
||||
dockerEnvCmd.Flags().BoolVarP(&unset, "unset", "u", false, "Unset variables instead of setting them")
|
||||
dockerEnvCmd.Flags().StringVar(&shell.ForceShell, "shell", "", "Force environment to be configured for a specified shell: [fish, cmd, powershell, tcsh, bash, zsh], default is auto-detect")
|
||||
dockerEnvCmd.Flags().BoolVarP(&dockerUnset, "unset", "u", false, "Unset variables instead of setting them")
|
||||
}
|
|
@ -32,15 +32,17 @@ func (f FakeNoProxyGetter) GetNoProxyVar() (string, string) {
|
|||
return f.NoProxyVar, f.NoProxyValue
|
||||
}
|
||||
|
||||
func TestGenerateScripts(t *testing.T) {
|
||||
func TestGenerateDockerScripts(t *testing.T) {
|
||||
var tests = []struct {
|
||||
config EnvConfig
|
||||
shell string
|
||||
config DockerEnvConfig
|
||||
noProxyGetter *FakeNoProxyGetter
|
||||
wantSet string
|
||||
wantUnset string
|
||||
}{
|
||||
{
|
||||
EnvConfig{profile: "bash", shell: "bash", driver: "kvm2", hostIP: "127.0.0.1", certsDir: "/certs"},
|
||||
"bash",
|
||||
DockerEnvConfig{profile: "bash", driver: "kvm2", hostIP: "127.0.0.1", certsDir: "/certs"},
|
||||
nil,
|
||||
`export DOCKER_TLS_VERIFY="1"
|
||||
export DOCKER_HOST="tcp://127.0.0.1:2376"
|
||||
|
@ -54,7 +56,8 @@ export MINIKUBE_ACTIVE_DOCKERD="bash"
|
|||
`,
|
||||
},
|
||||
{
|
||||
EnvConfig{profile: "ipv6", shell: "bash", driver: "kvm2", hostIP: "fe80::215:5dff:fe00:a903", certsDir: "/certs"},
|
||||
"bash",
|
||||
DockerEnvConfig{profile: "ipv6", driver: "kvm2", hostIP: "fe80::215:5dff:fe00:a903", certsDir: "/certs"},
|
||||
nil,
|
||||
`export DOCKER_TLS_VERIFY="1"
|
||||
export DOCKER_HOST="tcp://[fe80::215:5dff:fe00:a903]:2376"
|
||||
|
@ -68,7 +71,8 @@ export MINIKUBE_ACTIVE_DOCKERD="ipv6"
|
|||
`,
|
||||
},
|
||||
{
|
||||
EnvConfig{profile: "fish", shell: "fish", driver: "kvm2", hostIP: "127.0.0.1", certsDir: "/certs"},
|
||||
"fish",
|
||||
DockerEnvConfig{profile: "fish", driver: "kvm2", hostIP: "127.0.0.1", certsDir: "/certs"},
|
||||
nil,
|
||||
`set -gx DOCKER_TLS_VERIFY "1"
|
||||
set -gx DOCKER_HOST "tcp://127.0.0.1:2376"
|
||||
|
@ -85,7 +89,8 @@ set -e MINIKUBE_ACTIVE_DOCKERD
|
|||
`,
|
||||
},
|
||||
{
|
||||
EnvConfig{profile: "powershell", shell: "powershell", driver: "hyperv", hostIP: "192.168.0.1", certsDir: "/certs"},
|
||||
"powershell",
|
||||
DockerEnvConfig{profile: "powershell", driver: "hyperv", hostIP: "192.168.0.1", certsDir: "/certs"},
|
||||
nil,
|
||||
`$Env:DOCKER_TLS_VERIFY = "1"
|
||||
$Env:DOCKER_HOST = "tcp://192.168.0.1:2376"
|
||||
|
@ -99,7 +104,8 @@ $Env:MINIKUBE_ACTIVE_DOCKERD = "powershell"
|
|||
`,
|
||||
},
|
||||
{
|
||||
EnvConfig{profile: "cmd", shell: "cmd", driver: "hyperv", hostIP: "192.168.0.1", certsDir: "/certs"},
|
||||
"cmd",
|
||||
DockerEnvConfig{profile: "cmd", driver: "hyperv", hostIP: "192.168.0.1", certsDir: "/certs"},
|
||||
nil,
|
||||
`SET DOCKER_TLS_VERIFY=1
|
||||
SET DOCKER_HOST=tcp://192.168.0.1:2376
|
||||
|
@ -116,7 +122,8 @@ SET MINIKUBE_ACTIVE_DOCKERD=
|
|||
`,
|
||||
},
|
||||
{
|
||||
EnvConfig{profile: "emacs", shell: "emacs", driver: "hyperv", hostIP: "192.168.0.1", certsDir: "/certs"},
|
||||
"emacs",
|
||||
DockerEnvConfig{profile: "emacs", driver: "hyperv", hostIP: "192.168.0.1", certsDir: "/certs"},
|
||||
nil,
|
||||
`(setenv "DOCKER_TLS_VERIFY" "1")
|
||||
(setenv "DOCKER_HOST" "tcp://192.168.0.1:2376")
|
||||
|
@ -132,7 +139,8 @@ SET MINIKUBE_ACTIVE_DOCKERD=
|
|||
`,
|
||||
},
|
||||
{
|
||||
EnvConfig{profile: "bash-no-proxy", shell: "bash", driver: "kvm2", hostIP: "127.0.0.1", certsDir: "/certs", noProxy: true},
|
||||
"bash",
|
||||
DockerEnvConfig{profile: "bash-no-proxy", driver: "kvm2", hostIP: "127.0.0.1", certsDir: "/certs", noProxy: true},
|
||||
&FakeNoProxyGetter{"NO_PROXY", "127.0.0.1"},
|
||||
`export DOCKER_TLS_VERIFY="1"
|
||||
export DOCKER_HOST="tcp://127.0.0.1:2376"
|
||||
|
@ -148,7 +156,8 @@ export NO_PROXY="127.0.0.1"
|
|||
`,
|
||||
},
|
||||
{
|
||||
EnvConfig{profile: "bash-no-proxy-lower", shell: "bash", driver: "kvm2", hostIP: "127.0.0.1", certsDir: "/certs", noProxy: true},
|
||||
"bash",
|
||||
DockerEnvConfig{profile: "bash-no-proxy-lower", driver: "kvm2", hostIP: "127.0.0.1", certsDir: "/certs", noProxy: true},
|
||||
&FakeNoProxyGetter{"no_proxy", "127.0.0.1"},
|
||||
`export DOCKER_TLS_VERIFY="1"
|
||||
export DOCKER_HOST="tcp://127.0.0.1:2376"
|
||||
|
@ -164,7 +173,8 @@ export no_proxy="127.0.0.1"
|
|||
`,
|
||||
},
|
||||
{
|
||||
EnvConfig{profile: "powershell-no-proxy-idempotent", shell: "powershell", driver: "hyperv", hostIP: "192.168.0.1", certsDir: "/certs", noProxy: true},
|
||||
"powershell",
|
||||
DockerEnvConfig{profile: "powershell-no-proxy-idempotent", driver: "hyperv", hostIP: "192.168.0.1", certsDir: "/certs", noProxy: true},
|
||||
&FakeNoProxyGetter{"no_proxy", "192.168.0.1"},
|
||||
`$Env:DOCKER_TLS_VERIFY = "1"
|
||||
$Env:DOCKER_HOST = "tcp://192.168.0.1:2376"
|
||||
|
@ -179,7 +189,8 @@ $Env:no_proxy = "192.168.0.1"
|
|||
`,
|
||||
},
|
||||
{
|
||||
EnvConfig{profile: "sh-no-proxy-add", shell: "bash", driver: "kvm2", hostIP: "127.0.0.1", certsDir: "/certs", noProxy: true},
|
||||
"bash",
|
||||
DockerEnvConfig{profile: "sh-no-proxy-add", driver: "kvm2", hostIP: "127.0.0.1", certsDir: "/certs", noProxy: true},
|
||||
&FakeNoProxyGetter{"NO_PROXY", "192.168.0.1,10.0.0.4"},
|
||||
`export DOCKER_TLS_VERIFY="1"
|
||||
export DOCKER_HOST="tcp://127.0.0.1:2376"
|
||||
|
@ -197,10 +208,11 @@ export NO_PROXY="192.168.0.1,10.0.0.4,127.0.0.1"
|
|||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.config.profile, func(t *testing.T) {
|
||||
tc.config.EnvConfig.Shell = tc.shell
|
||||
defaultNoProxyGetter = tc.noProxyGetter
|
||||
var b []byte
|
||||
buf := bytes.NewBuffer(b)
|
||||
if err := setScript(tc.config, buf); err != nil {
|
||||
if err := dockerSetScript(tc.config, buf); err != nil {
|
||||
t.Errorf("setScript(%+v) error: %v", tc.config, err)
|
||||
}
|
||||
got := buf.String()
|
||||
|
@ -209,7 +221,7 @@ export NO_PROXY="192.168.0.1,10.0.0.4,127.0.0.1"
|
|||
}
|
||||
|
||||
buf = bytes.NewBuffer(b)
|
||||
if err := unsetScript(tc.config, buf); err != nil {
|
||||
if err := dockerUnsetScript(tc.config, buf); err != nil {
|
||||
t.Errorf("unsetScript(%+v) error: %v", tc.config, err)
|
||||
}
|
||||
got = buf.String()
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
Copyright 2020 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Part of this code is heavily inspired/copied by the following file:
|
||||
// github.com/docker/machine/commands/env.go
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/machine/libmachine/drivers"
|
||||
"github.com/docker/machine/libmachine/host"
|
||||
"github.com/docker/machine/libmachine/ssh"
|
||||
"github.com/docker/machine/libmachine/state"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"k8s.io/minikube/pkg/minikube/cluster"
|
||||
"k8s.io/minikube/pkg/minikube/config"
|
||||
"k8s.io/minikube/pkg/minikube/constants"
|
||||
"k8s.io/minikube/pkg/minikube/driver"
|
||||
"k8s.io/minikube/pkg/minikube/exit"
|
||||
"k8s.io/minikube/pkg/minikube/machine"
|
||||
"k8s.io/minikube/pkg/minikube/out"
|
||||
"k8s.io/minikube/pkg/minikube/shell"
|
||||
)
|
||||
|
||||
var podmanEnvTmpl = fmt.Sprintf("{{ .Prefix }}%s{{ .Delimiter }}{{ .VarlinkBridge }}{{ .Suffix }}{{ .UsageHint }}", constants.PodmanVarlinkBridgeEnv)
|
||||
|
||||
// PodmanShellConfig represents the shell config for Podman
|
||||
type PodmanShellConfig struct {
|
||||
shell.Config
|
||||
VarlinkBridge string
|
||||
}
|
||||
|
||||
var (
|
||||
podmanUnset bool
|
||||
)
|
||||
|
||||
// podmanShellCfgSet generates context variables for "podman-env"
|
||||
func podmanShellCfgSet(ec PodmanEnvConfig, envMap map[string]string) *PodmanShellConfig {
|
||||
profile := ec.profile
|
||||
const usgPlz = "To point your shell to minikube's podman service, run:"
|
||||
var usgCmd = fmt.Sprintf("minikube -p %s podman-env", profile)
|
||||
s := &PodmanShellConfig{
|
||||
Config: *shell.CfgSet(ec.EnvConfig, usgPlz, usgCmd),
|
||||
}
|
||||
s.VarlinkBridge = envMap[constants.PodmanVarlinkBridgeEnv]
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// isPodmanAvailable checks if Podman is available
|
||||
func isPodmanAvailable(host *host.Host) (bool, error) {
|
||||
// we need both "varlink bridge" and "podman varlink"
|
||||
if _, err := host.RunSSHCommand("which varlink"); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if _, err := host.RunSSHCommand("which podman"); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func createExternalSSHClient(d drivers.Driver) (*ssh.ExternalClient, error) {
|
||||
sshBinaryPath, err := exec.LookPath("ssh")
|
||||
if err != nil {
|
||||
return &ssh.ExternalClient{}, err
|
||||
}
|
||||
|
||||
addr, err := d.GetSSHHostname()
|
||||
if err != nil {
|
||||
return &ssh.ExternalClient{}, err
|
||||
}
|
||||
|
||||
port, err := d.GetSSHPort()
|
||||
if err != nil {
|
||||
return &ssh.ExternalClient{}, err
|
||||
}
|
||||
|
||||
auth := &ssh.Auth{}
|
||||
if d.GetSSHKeyPath() != "" {
|
||||
auth.Keys = []string{d.GetSSHKeyPath()}
|
||||
}
|
||||
|
||||
return ssh.NewExternalClient(sshBinaryPath, d.GetSSHUsername(), addr, port, auth)
|
||||
}
|
||||
|
||||
// podmanEnvCmd represents the podman-env command
|
||||
var podmanEnvCmd = &cobra.Command{
|
||||
Use: "podman-env",
|
||||
Short: "Sets up podman env variables; similar to '$(podman-machine env)'",
|
||||
Long: `Sets up podman env variables; similar to '$(podman-machine env)'.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
api, err := machine.NewAPIClient()
|
||||
if err != nil {
|
||||
exit.WithError("Error getting client", err)
|
||||
}
|
||||
defer api.Close()
|
||||
|
||||
profile := viper.GetString(config.MachineProfile)
|
||||
cc, err := config.Load(profile)
|
||||
if err != nil {
|
||||
exit.WithError("Error getting config", err)
|
||||
}
|
||||
host, err := cluster.CheckIfHostExistsAndLoad(api, cc.Name)
|
||||
if err != nil {
|
||||
exit.WithError("Error getting host", err)
|
||||
}
|
||||
if host.Driver.DriverName() == driver.None {
|
||||
exit.UsageT(`'none' driver does not support 'minikube podman-env' command`)
|
||||
}
|
||||
|
||||
hostSt, err := cluster.GetHostStatus(api, cc.Name)
|
||||
if err != nil {
|
||||
exit.WithError("Error getting host status", err)
|
||||
}
|
||||
if hostSt != state.Running.String() {
|
||||
exit.WithCodeT(exit.Unavailable, `'{{.profile}}' is not running`, out.V{"profile": profile})
|
||||
}
|
||||
ok, err := isPodmanAvailable(host)
|
||||
if err != nil {
|
||||
exit.WithError("Error getting service status", err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
exit.WithCodeT(exit.Unavailable, `The podman service within '{{.profile}}' is not active`, out.V{"profile": profile})
|
||||
}
|
||||
|
||||
client, err := createExternalSSHClient(host.Driver)
|
||||
if err != nil {
|
||||
exit.WithError("Error getting ssh client", err)
|
||||
}
|
||||
|
||||
sh := shell.EnvConfig{
|
||||
Shell: shell.ForceShell,
|
||||
}
|
||||
ec := PodmanEnvConfig{
|
||||
EnvConfig: sh,
|
||||
profile: profile,
|
||||
driver: host.DriverName,
|
||||
client: client,
|
||||
}
|
||||
|
||||
if ec.Shell == "" {
|
||||
ec.Shell, err = shell.Detect()
|
||||
if err != nil {
|
||||
exit.WithError("Error detecting shell", err)
|
||||
}
|
||||
}
|
||||
|
||||
if podmanUnset {
|
||||
if err := podmanUnsetScript(ec, os.Stdout); err != nil {
|
||||
exit.WithError("Error generating unset output", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := podmanSetScript(ec, os.Stdout); err != nil {
|
||||
exit.WithError("Error generating set output", err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// PodmanEnvConfig encapsulates all external inputs into shell generation for Podman
|
||||
type PodmanEnvConfig struct {
|
||||
shell.EnvConfig
|
||||
profile string
|
||||
driver string
|
||||
client *ssh.ExternalClient
|
||||
}
|
||||
|
||||
// podmanSetScript writes out a shell-compatible 'podman-env' script
|
||||
func podmanSetScript(ec PodmanEnvConfig, w io.Writer) error {
|
||||
envVars, err := podmanEnvVars(ec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return shell.SetScript(ec.EnvConfig, w, podmanEnvTmpl, podmanShellCfgSet(ec, envVars))
|
||||
}
|
||||
|
||||
// podmanUnsetScript writes out a shell-compatible 'podman-env unset' script
|
||||
func podmanUnsetScript(ec PodmanEnvConfig, w io.Writer) error {
|
||||
vars := []string{
|
||||
constants.PodmanVarlinkBridgeEnv,
|
||||
}
|
||||
return shell.UnsetScript(ec.EnvConfig, w, vars)
|
||||
}
|
||||
|
||||
// podmanBridge returns the command to use in a var for accessing the podman varlink bridge over ssh
|
||||
func podmanBridge(client *ssh.ExternalClient) string {
|
||||
command := []string{client.BinaryPath}
|
||||
command = append(command, client.BaseArgs...)
|
||||
command = append(command, "--", "sudo", "varlink", "-A", `\'podman varlink \\\$VARLINK_ADDRESS\'`, "bridge")
|
||||
return strings.Join(command, " ")
|
||||
}
|
||||
|
||||
// podmanEnvVars gets the necessary podman env variables to allow the use of minikube's podman service
|
||||
func podmanEnvVars(ec PodmanEnvConfig) (map[string]string, error) { // nolint result 1 (error) is always nil
|
||||
env := map[string]string{
|
||||
constants.PodmanVarlinkBridgeEnv: podmanBridge(ec.client),
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
podmanEnvCmd.Flags().StringVar(&shell.ForceShell, "shell", "", "Force environment to be configured for a specified shell: [fish, cmd, powershell, tcsh, bash, zsh], default is auto-detect")
|
||||
podmanEnvCmd.Flags().BoolVarP(&podmanUnset, "unset", "u", false, "Unset variables instead of setting them")
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
Copyright 2020 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/machine/libmachine/ssh"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func newFakeClient() *ssh.ExternalClient {
|
||||
return &ssh.ExternalClient{
|
||||
BaseArgs: []string{"root@host"},
|
||||
BinaryPath: "/usr/bin/ssh",
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeneratePodmanScripts(t *testing.T) {
|
||||
var tests = []struct {
|
||||
shell string
|
||||
config PodmanEnvConfig
|
||||
noProxyGetter *FakeNoProxyGetter
|
||||
wantSet string
|
||||
wantUnset string
|
||||
}{
|
||||
{
|
||||
"bash",
|
||||
PodmanEnvConfig{profile: "bash", driver: "kvm2", client: newFakeClient()},
|
||||
nil,
|
||||
`export PODMAN_VARLINK_BRIDGE="/usr/bin/ssh root@host -- sudo varlink -A \'podman varlink \\\$VARLINK_ADDRESS\' bridge"
|
||||
|
||||
# To point your shell to minikube's podman service, run:
|
||||
# eval $(minikube -p bash podman-env)
|
||||
`,
|
||||
`unset PODMAN_VARLINK_BRIDGE
|
||||
`,
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.config.profile, func(t *testing.T) {
|
||||
tc.config.EnvConfig.Shell = tc.shell
|
||||
defaultNoProxyGetter = tc.noProxyGetter
|
||||
var b []byte
|
||||
buf := bytes.NewBuffer(b)
|
||||
if err := podmanSetScript(tc.config, buf); err != nil {
|
||||
t.Errorf("setScript(%+v) error: %v", tc.config, err)
|
||||
}
|
||||
got := buf.String()
|
||||
if diff := cmp.Diff(tc.wantSet, got); diff != "" {
|
||||
t.Errorf("setScript(%+v) mismatch (-want +got):\n%s\n\nraw output:\n%s\nquoted: %q", tc.config, diff, got, got)
|
||||
}
|
||||
|
||||
buf = bytes.NewBuffer(b)
|
||||
if err := podmanUnsetScript(tc.config, buf); err != nil {
|
||||
t.Errorf("unsetScript(%+v) error: %v", tc.config, err)
|
||||
}
|
||||
got = buf.String()
|
||||
if diff := cmp.Diff(tc.wantUnset, got); diff != "" {
|
||||
t.Errorf("unsetScript(%+v) mismatch (-want +got):\n%s\n\nraw output:\n%s\nquoted: %q", tc.config, diff, got, got)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
|
@ -180,6 +180,7 @@ func init() {
|
|||
Message: translate.T("Images Commands:"),
|
||||
Commands: []*cobra.Command{
|
||||
dockerEnvCmd,
|
||||
podmanEnvCmd,
|
||||
cacheCmd,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -50,6 +50,8 @@ const (
|
|||
// DockerDaemonEnvs has list of environment variables to control docker daemon shell is using
|
||||
|
||||
MinikubeActiveDockerdEnv = "MINIKUBE_ACTIVE_DOCKERD"
|
||||
// PodmanVarlinkBridgeEnv is used for podman settings
|
||||
PodmanVarlinkBridgeEnv = "PODMAN_VARLINK_BRIDGE"
|
||||
)
|
||||
|
||||
var DockerDaemonEnvs = [3]string{DockerHostEnv, DockerTLSVerifyEnv, DockerCertPathEnv}
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
Copyright 2020 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Part of this code is heavily inspired/copied by the following file:
|
||||
// github.com/docker/machine/commands/env.go
|
||||
|
||||
package shell
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/docker/machine/libmachine/shell"
|
||||
)
|
||||
|
||||
const (
|
||||
fishSetPfx = "set -gx "
|
||||
fishSetSfx = "\"\n"
|
||||
fishSetDelim = " \""
|
||||
|
||||
fishUnsetPfx = "set -e "
|
||||
fishUnsetSfx = "\n"
|
||||
|
||||
psSetPfx = "$Env:"
|
||||
psSetSfx = "\"\n"
|
||||
psSetDelim = " = \""
|
||||
|
||||
psUnsetPfx = `Remove-Item Env:\\`
|
||||
psUnsetSfx = "\n"
|
||||
|
||||
cmdSetPfx = "SET "
|
||||
cmdSetSfx = "\n"
|
||||
cmdSetDelim = "="
|
||||
|
||||
cmdUnsetPfx = "SET "
|
||||
cmdUnsetSfx = "\n"
|
||||
cmdUnsetDelim = "="
|
||||
|
||||
emacsSetPfx = "(setenv \""
|
||||
emacsSetSfx = "\")\n"
|
||||
emacsSetDelim = "\" \""
|
||||
|
||||
emacsUnsetPfx = "(setenv \""
|
||||
emacsUnsetSfx = ")\n"
|
||||
emacsUnsetDelim = "\" nil"
|
||||
|
||||
bashSetPfx = "export "
|
||||
bashSetSfx = "\"\n"
|
||||
bashSetDelim = "=\""
|
||||
|
||||
bashUnsetPfx = "unset "
|
||||
bashUnsetSfx = "\n"
|
||||
|
||||
nonePfx = ""
|
||||
noneSfx = "\n"
|
||||
noneDelim = "="
|
||||
)
|
||||
|
||||
// Config represents the shell config
|
||||
type Config struct {
|
||||
Prefix string
|
||||
Delimiter string
|
||||
Suffix string
|
||||
UsageHint string
|
||||
}
|
||||
|
||||
var (
|
||||
// ForceShell forces a shell name
|
||||
ForceShell string
|
||||
)
|
||||
|
||||
// Detect detects user's current shell.
|
||||
func Detect() (string, error) {
|
||||
return shell.Detect()
|
||||
}
|
||||
|
||||
func generateUsageHint(sh, usgPlz, usgCmd string) string {
|
||||
var usageHintMap = map[string]string{
|
||||
"bash": fmt.Sprintf(`
|
||||
# %s
|
||||
# eval $(%s)
|
||||
`, usgPlz, usgCmd),
|
||||
"fish": fmt.Sprintf(`
|
||||
# %s
|
||||
# eval (%s)
|
||||
`, usgPlz, usgCmd),
|
||||
"powershell": fmt.Sprintf(`# %s
|
||||
# & %s | Invoke-Expression
|
||||
`, usgPlz, usgCmd),
|
||||
"cmd": fmt.Sprintf(`REM %s
|
||||
REM @FOR /f "tokens=*" %%i IN ('%s') DO @%%i
|
||||
`, usgPlz, usgCmd),
|
||||
"emacs": fmt.Sprintf(`;; %s
|
||||
;; (with-temp-buffer (shell-command "%s" (current-buffer)) (eval-buffer))
|
||||
`, usgPlz, usgCmd),
|
||||
}
|
||||
|
||||
hint, ok := usageHintMap[sh]
|
||||
if !ok {
|
||||
return usageHintMap["bash"]
|
||||
}
|
||||
return hint
|
||||
}
|
||||
|
||||
// CfgSet generates context variables for shell
|
||||
func CfgSet(ec EnvConfig, plz, cmd string) *Config {
|
||||
s := &Config{
|
||||
UsageHint: generateUsageHint(ec.Shell, plz, cmd),
|
||||
}
|
||||
|
||||
switch ec.Shell {
|
||||
case "fish":
|
||||
s.Prefix = fishSetPfx
|
||||
s.Suffix = fishSetSfx
|
||||
s.Delimiter = fishSetDelim
|
||||
case "powershell":
|
||||
s.Prefix = psSetPfx
|
||||
s.Suffix = psSetSfx
|
||||
s.Delimiter = psSetDelim
|
||||
case "cmd":
|
||||
s.Prefix = cmdSetPfx
|
||||
s.Suffix = cmdSetSfx
|
||||
s.Delimiter = cmdSetDelim
|
||||
case "emacs":
|
||||
s.Prefix = emacsSetPfx
|
||||
s.Suffix = emacsSetSfx
|
||||
s.Delimiter = emacsSetDelim
|
||||
case "none":
|
||||
s.Prefix = nonePfx
|
||||
s.Suffix = noneSfx
|
||||
s.Delimiter = noneDelim
|
||||
s.UsageHint = ""
|
||||
default:
|
||||
s.Prefix = bashSetPfx
|
||||
s.Suffix = bashSetSfx
|
||||
s.Delimiter = bashSetDelim
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// EnvConfig encapsulates all external inputs into shell generation
|
||||
type EnvConfig struct {
|
||||
Shell string
|
||||
}
|
||||
|
||||
// SetScript writes out a shell-compatible set script
|
||||
func SetScript(ec EnvConfig, w io.Writer, envTmpl string, data interface{}) error {
|
||||
tmpl := template.Must(template.New("envConfig").Parse(envTmpl))
|
||||
return tmpl.Execute(w, data)
|
||||
}
|
||||
|
||||
// UnsetScript writes out a shell-compatible unset script
|
||||
func UnsetScript(ec EnvConfig, w io.Writer, vars []string) error {
|
||||
var sb strings.Builder
|
||||
switch ec.Shell {
|
||||
case "fish":
|
||||
for _, v := range vars {
|
||||
sb.WriteString(fmt.Sprintf("%s%s%s", fishUnsetPfx, v, fishUnsetSfx))
|
||||
}
|
||||
case "powershell":
|
||||
sb.WriteString(fmt.Sprintf("%s%s%s", psUnsetPfx, strings.Join(vars, " Env:\\\\"), psUnsetSfx))
|
||||
case "cmd":
|
||||
for _, v := range vars {
|
||||
sb.WriteString(fmt.Sprintf("%s%s%s%s", cmdUnsetPfx, v, cmdUnsetDelim, cmdUnsetSfx))
|
||||
}
|
||||
case "emacs":
|
||||
for _, v := range vars {
|
||||
sb.WriteString(fmt.Sprintf("%s%s%s%s", emacsUnsetPfx, v, emacsUnsetDelim, emacsUnsetSfx))
|
||||
}
|
||||
case "none":
|
||||
sb.WriteString(fmt.Sprintf("%s%s%s", nonePfx, strings.Join(vars, " "), noneSfx))
|
||||
default:
|
||||
sb.WriteString(fmt.Sprintf("%s%s%s", bashUnsetPfx, strings.Join(vars, " "), bashUnsetSfx))
|
||||
}
|
||||
_, err := w.Write([]byte(sb.String()))
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
title: "Using the Podman service"
|
||||
linkTitle: "Using the Podman service"
|
||||
weight: 6
|
||||
date: 2020-01-20
|
||||
description: >
|
||||
How to access the Podman service within minikube
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You should be using minikube with the container runtime set to CRI-O. It uses the same storage as Podman.
|
||||
|
||||
## Method 1: Without minikube registry addon
|
||||
|
||||
When using a single VM of Kubernetes it's really handy to reuse the Podman service inside the VM; as this means you don't have to build on your host machine and push the image into a container registry - you can just build inside the same container storage as minikube which speeds up local experiments.
|
||||
|
||||
To be able to work with the podman client on your mac/linux host use the podman-env command in your shell:
|
||||
|
||||
```shell
|
||||
eval $(minikube podman-env)
|
||||
```
|
||||
|
||||
You should now be able to use podman on the command line on your host mac/linux machine talking to the podman service inside the minikube VM:
|
||||
|
||||
```shell
|
||||
podman-remote help
|
||||
```
|
||||
|
||||
Remember to turn off the _imagePullPolicy:Always_, as otherwise Kubernetes won't use images you built locally.
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [docker_registry.md](Using the Docker registry)
|
Loading…
Reference in New Issue