Skip to content

Commit

Permalink
Merge pull request #3495 from telepresenceio/thallgren/cli-in-docker
Browse files Browse the repository at this point in the history
Restore ability to run the telepresence CLI in a docker container.
  • Loading branch information
thallgren authored Jan 30, 2024
2 parents bf3ea64 + 5f57ee0 commit 673a9c5
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 20 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ items:
<tr><td><code>pods</code></td><td>The cluster's pod subnets.</td></tr>
<tr><td><code>all</code></td><td>All of the above.</td></tr>
</table></p>
- type: bugfix
title: Restore ability to run the telepresence CLI in a docker container.
body: >-
The improvements made to be able to run the telepresence daemon in docker
using <code>telepresence connect --docker</code> made it impossible to run
both the CLI and the daemon in docker. This commit fixes that and
also ensures that the user- and root-daemons are merged in this
scenario when the container runs as root.
- type: bugfix
title: Kubeconfig exec authentication with context names containing colon didn't work on Windows
body: >-
Expand Down
5 changes: 5 additions & 0 deletions integration_test/testdata/cli-container/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM telepresence

RUN apk add --no-cache bash curl

ENTRYPOINT ["/bin/bash"]
48 changes: 31 additions & 17 deletions pkg/client/cli/connect/connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,9 @@ func quitDockerDaemons(ctx context.Context) {
func DialDaemon(ctx context.Context, info *daemon.Info) (*grpc.ClientConn, error) {
var err error
var conn *grpc.ClientConn
if info.InDocker {
var addr string
daemonID := info.DaemonID()
if proc.RunningInContainer() {
// Containers use the daemon container DNS name
addr = fmt.Sprintf("%s:%d", daemonID.ContainerName(), info.DaemonPort)
} else {
// The host relies on that the daemon has exposed a port to localhost
addr = fmt.Sprintf(":%d", info.DaemonPort)
}
conn, err = docker.ConnectDaemon(ctx, addr)
if info.InDocker && !proc.RunningInContainer() {
// The host relies on that the daemon has exposed a port to localhost
conn, err = docker.ConnectDaemon(ctx, fmt.Sprintf(":%d", info.DaemonPort))
} else {
// Try dialing the host daemon using the well known socket.
conn, err = socket.Dial(ctx, socket.UserDaemonPath(ctx))
Expand Down Expand Up @@ -162,7 +154,7 @@ func DiscoverDaemon(ctx context.Context, match *regexp.Regexp, kubeContext, name
if os.IsNotExist(err) {
// Try dialing the host daemon using the well known socket.
if conn, sockErr := socket.Dial(ctx, socket.UserDaemonPath(ctx)); sockErr == nil {
daemonID, err := daemon.NewIdentifier("", kubeContext, namespace, false)
daemonID, err := daemon.NewIdentifier("", kubeContext, namespace, proc.RunningInContainer())
if err != nil {
return nil, err
}
Expand All @@ -179,19 +171,20 @@ func DiscoverDaemon(ctx context.Context, match *regexp.Regexp, kubeContext, name

func launchConnectorDaemon(ctx context.Context, connectorDaemon string, required bool) (context.Context, *daemon.UserClient, error) {
cr := daemon.GetRequest(ctx)
daemonID, err := daemon.IdentifierFromFlags(cr.Name, cr.KubeFlags, cr.Docker)
cliInContainer := proc.RunningInContainer()
daemonID, err := daemon.IdentifierFromFlags(cr.Name, cr.KubeFlags, cr.Docker || cliInContainer)
if err != nil {
return ctx, nil, err
}

// Try dialing the host daemon using the well known socket.
ud, err := DiscoverDaemon(ctx, cr.Use, daemonID.KubeContext, daemonID.Namespace)
if err == nil {
if ud.Containerized() {
if ud.Containerized() && !cliInContainer {
ctx = docker.EnableClient(ctx)
cr.Docker = true
}
if ud.Containerized() == cr.Docker {
if ud.Containerized() == (cr.Docker || cliInContainer) {
return ctx, ud, nil
}
// A daemon running on the host does not fulfill a request for a containerized daemon. They can
Expand All @@ -214,7 +207,7 @@ func launchConnectorDaemon(ctx context.Context, connectorDaemon string, required
}

var conn *grpc.ClientConn
if cr.Docker {
if cr.Docker && !cliInContainer {
// Ensure that the logfile is present before the daemon starts so that it isn't created with
// permissions from the docker container.
logDir := filelocation.AppUserLogDir(ctx)
Expand All @@ -236,13 +229,34 @@ func launchConnectorDaemon(ctx context.Context, connectorDaemon string, required
if cr.UserDaemonProfilingPort > 0 {
args = append(args, "--pprof", strconv.Itoa(int(cr.UserDaemonProfilingPort)))
}
if cliInContainer && os.Getuid() == 0 {
// No use having multiple daemons when running as root in docker.
hn, err := os.Hostname()
if err != nil {
hn = "unknown"
}
args = append(args, "--embed-network")
args = append(args, "--name", "docker-"+hn)
}
if err = proc.StartInBackground(false, args...); err != nil {
return ctx, nil, errcat.NoDaemonLogs.Newf("failed to launch the connector service: %w", err)
}
if err = socket.WaitUntilAppears("connector", socket.UserDaemonPath(ctx), 10*time.Second); err != nil {
return ctx, nil, errcat.NoDaemonLogs.Newf("connector service did not start: %w", err)
}
conn, err = socket.Dial(ctx, socket.UserDaemonPath(ctx))
if err == nil {
err = daemon.SaveInfo(ctx,
&daemon.Info{
InDocker: cliInContainer,
DaemonPort: 0,
Name: daemonID.Name,
KubeContext: daemonID.KubeContext,
Namespace: daemonID.Namespace,
ExposedPorts: cr.ExposedPorts,
Hostname: cr.Hostname,
}, daemonID.InfoFileName())
}
}
if err != nil {
return ctx, nil, err
Expand Down Expand Up @@ -304,7 +318,7 @@ func EnsureSession(ctx context.Context, useLine string, required bool) (context.
func connectSession(ctx context.Context, useLine string, userD *daemon.UserClient, request *daemon.Request, required bool) (*daemon.Session, error) {
var ci *connector.ConnectInfo
var err error
if userD.Containerized() {
if userD.Containerized() && !proc.RunningInContainer() {
patcher.AnnotateConnectRequest(&request.ConnectRequest, docker.TpCache, userD.DaemonID.KubeContext)
}
cat := errcat.Unknown
Expand Down
14 changes: 11 additions & 3 deletions pkg/proc/docker.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
package proc

import "os"
import (
"os"
)

var runningInContainer bool //nolint:gochecknoglobals // this is a constant

func init() {
_, err := os.Stat("/.dockerenv")
runningInContainer = err == nil
}

// RunningInContainer returns true if the current process runs from inside a docker container.
func RunningInContainer() bool {
_, err := os.Stat("/.dockerenv")
return err == nil
return runningInContainer
}

0 comments on commit 673a9c5

Please sign in to comment.