Die Docker-Version hängt vor den Serverinformationen

3

Einführung

Ich versuche, die folgende Version von dockerauf einer Linux-VM zu verwenden ( uname -aRückgabe Linux xen 4.1.17-yocto-standard #1 SMP PREEMPT Thu Jun 2 13:29:47 PDT 2016 x86_64 GNU/Linux), erstellt aus dem docker_gitBitBake-Rezept) .

Wenn ich versuche zu laufen docker version, erhalte ich die folgende Ausgabe:

Client version: 1.6.2
Client API version: 1.18
Go version (client): go1.3
Git commit (client): 7c8fca2-dirty
OS/Arch (client): linux/amd64

Dann hängt der Befehl.

Wie es aussehen soll

Ich habe versucht, docker versionauf einer funktionierenden Docker-Installation (Ubuntu 14.04) auszuführen , und erhalte die folgende Ausgabe:

Client version: 1.6.2
Client API version: 1.18
Go version (client): go1.2.1
Git commit (client): 7c8fca2
OS/Arch (client): linux/amd64
Server version: 1.6.2
Server API version: 1.18
Go version (server): go1.2.1
Git commit (server): 7c8fca2
OS/Arch (server): linux/amd64

Ich gehe also davon aus, dass beim Abrufen der Serverinformationen ein Fehler auftritt.

Zusätzliche Forschung

Ich bin nicht mit Go vertraut, daher kann dieser Abschnitt erschütternd sein, wenn ich versuche herauszufinden, was zum Teufel hier vor sich geht.

Ich fing an, mir diesen Teil des api/client/version.goDocker-Quellcodes anzusehen:

var versionTemplate = `Client:
 Version:      {{.Client.Version}}
 API version:  {{.Client.APIVersion}}
 Go version:   {{.Client.GoVersion}}
 Git commit:   {{.Client.GitCommit}}
 Built:        {{.Client.BuildTime}}
 OS/Arch:      {{.Client.Os}}/{{.Client.Arch}}{{if .Client.Experimental}}
 Experimental: {{.Client.Experimental}}{{end}}{{if .ServerOK}}
Server:
 Version:      {{.Server.Version}}
 API version:  {{.Server.APIVersion}}
 Go version:   {{.Server.GoVersion}}
 Git commit:   {{.Server.GitCommit}}
 Built:        {{.Server.BuildTime}}
 OS/Arch:      {{.Server.Os}}/{{.Server.Arch}}{{if .Server.Experimental}}
 Experimental: {{.Server.Experimental}}{{end}}{{end}}`

Es geht weiter zu diesem Abschnitt:

vd := types.VersionResponse{
    Client: &types.Version{
        Version:      dockerversion.Version,
        APIVersion:   cli.client.ClientVersion(),
        GoVersion:    runtime.Version(),
        GitCommit:    dockerversion.GitCommit,
        BuildTime:    dockerversion.BuildTime,
        Os:           runtime.GOOS,
        Arch:         runtime.GOARCH,
        Experimental: utils.ExperimentalBuild(),
    },
}

Von engine-api/types/client.go:

// VersionResponse holds version information for the client and the server
type VersionResponse struct {
    Client *Version
    Server *Version
} 

An dieser Stelle müssen Sie dem ServerMitglied (vom Typ *Version) lediglich etwas zuweisen . Dies geschieht in dem Abschnitt nach der vdZuordnung von oben:

serverVersion, err := cli.client.ServerVersion(context.Background())
if err == nil {
    vd.Server = &serverVersion
}

Die Funktionsdefinition für ServerVersionist die folgende vonengine-api/client/version.go

// ServerVersion returns information of the docker client and server host.
func (cli *Client) ServerVersion(ctx context.Context) (types.Version, error) {
    resp, err := cli.get(ctx, "/version", nil, nil)
    if err != nil {
        return types.Version{}, err
    }

    var server types.Version
    err = json.NewDecoder(resp.body).Decode(&server)
    ensureReaderClosed(resp)
    return server, err
}

Soweit ich das beurteilen kann, getverweist der obige Funktionsaufruf auf client/request.goDockers engine APIRepo

// getWithContext sends an http request to the docker API using the method GET with a specific go context.
func (cli *Client) get(ctx context.Context, path string, query url.Values, headers map[string][]string) (*serverResponse, error) {
    return cli.sendRequest(ctx, "GET", path, query, nil, headers)
}

Woher:

  • ctx ist context.Background()
  • path ist /version
  • Nein query
  • Nein headers

Und diese Dokumentation für sendRequestvon vendor/src/google.golang.org/grpc/call.go:

// sendRequest writes out various information of an RPC such as Context and Message.
func sendRequest(ctx context.Context, codec Codec, callHdr *transport.CallHdr, t transport.ClientTransport, args interface{}, opts *transport.Options) (_ *transport.Stream, err error) {
    stream, err := t.NewStream(ctx, callHdr)
    if err != nil {
        return nil, err
    }
    defer func() {
        if err != nil {
            if _, ok := err.(transport.ConnectionError); !ok {
                t.CloseStream(stream, err)
            }
        }
    }()
    // TODO(zhaoq): Support compression.
    outBuf, err := encode(codec, args, compressionNone)
    if err != nil {
        return nil, transport.StreamErrorf(codes.Internal, "grpc: %v", err)
    }
    err = t.Write(stream, outBuf, opts)
    if err != nil {
        return nil, err
    }
    // Sent successfully.
    return stream, nil
}

Dies ist seit einiger Zeit eine Vermutung und ich mache mir jetzt Sorgen, dass ich möglicherweise am falschen Ort suche.

Fragen

  • Was verursacht docker version, docker run hello-world, docker images, docker ps, und docker infohängen und wie sie behoben werden?
  • Oder gibt es eine effektivere Möglichkeit, die Ursache dieses Fehlers zu untersuchen?
Karobar
quelle
Welches Betriebssystem verwenden Sie? Haben Sie versucht, eine neuere Docker-Version zu installieren?
Ken J
Dies ist eine sehr spezifische Frage zu einem sehr spezifischen Projekt, was mich gerade beeindruckt hat. This package contains the daemon and client. Using docker.io on non-amd64 hosts is not supported at this time.Sind Sie sicher, dass Sie es auf einem AMD-Prozessor und nicht auf Intel ausführen?
Vojtěch Dohnal
Ich habe es auf einer virtuellen Intel-CPU ausgeführt. Auf Kens Frage hin ist das Betriebssystem Homebrew mit Linux 4.1-Kernel. Ich habe auch versucht, 1.11 mit ähnlichen Effekten zu installieren. Ich werde die Frage bald aktualisieren.
Karobar
Sie sollten straceden Prozess / Daemon verwenden, der den Socket überwacht /var/run/docker.sock. Ihr docker infoBefehl hat eine Anforderung an den Socket gesendet, die mit "GET /v1.18/info HTTP / 1.1 \ r \ nHost:" beginnt, und hat ewig auf eine Antwort gewartet, aber der Server hat nicht geantwortet.
Deltik

Antworten:

3

In Ihrer straceAusgabe wird dringend empfohlen, dass der Docker-Client nicht mit dem Docker-Daemon kommunizieren kann, der standardmäßig einen Socket unter erstellt /var/run/docker.sock.

Der Docker-Daemon sollte ein Systemdienst sein (auf systemd, in /lib/systemd/system/docker.serviceder Socket-Konfiguration unter /lib/systemd/system/docker.socket), kann jedoch unabhängig mit gestartet werden, /usr/bin/docker daemongefolgt von optionalen Optionen.

Sie sollten straceden Daemon und nicht den Client .

Verwendung straceauf dem Docker-Daemon

  1. Rufen Sie die Prozess-ID Ihres Docker-Daemons ab. Jeder dieser Befehle würde die PID in einer aufgerufenen Variablen speichern $DOCKER_PID.

    • Direkt aus der Steckdose:

      DOCKER_PID=$(sudo lsof -Ua /var/run/docker.sock | awk '/^docker/ {print $2}' | head -1)
      
    • systemd:

      DOCKER_PID=$(systemctl show -p MainPID docker.service | awk -F'=' '{print $NF}')
      
    • Andere:

      DOCKER_PID=$(ps aux | grep 'docker daemon' | grep -v 'grep' | awk '{print $2}' | head -1)
      
  2. Verwenden Sie straceauf dem Docker-Daemon jetzt, da Sie die PID haben:

    sudo strace -vvvfts1000 -p $DOCKER_PID
    
  3. Führen Sie in einem separaten Terminal einen Befehl aus, der normalerweise im Docker-Client hängt.

    docker version
    
  4. Beobachten Sie den straceOn-the-Docker-Daemon, um zu sehen, was ab dem hörenden Ende des Sockets geschieht.

Interpretation der straceAusgabe

Hier ist, was der Daemon tun soll, wenn Sie ausführen docker version:

  1. Lesen Sie, was der Kunde gesendet hat:

    [pid 14291] 12:34:36 <... read resumed> "GET /v1.22/version HTTP/1.1\r\nHost: \r\nUser-Agent: Docker-Client/1.10.3 (linux)\r\n\r\n", 4096) = 81
    
  2. Sammeln Sie Informationen über das System:

    [pid 14291] 12:34:36 uname({sysname="Linux", nodename="node51", release="4.4.0-22-generic", version="#40-Ubuntu SMP Thu May 12 22:03:46 UTC 2016", machine="x86_64", domainname="(none)"}) = 0
    
  3. Antworte dem Kunden mit Informationen über das System:

    [pid 14291] 12:34:36 write(3, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nServer: Docker/1.10.3 (linux)\r\nDate: Mon, 13 Jun 2016 17:34:36 GMT\r\nContent-Length: 194\r\n\r\n{\"Version\":\"1.10.3\",\"ApiVersion\":\"1.22\",\"GitCommit\":\"20f81dd\",\"GoVersion\":\"go1.6.1\",\"Os\":\"linux\",\"Arch\":\"amd64\",\"KernelVersion\":\"4.4.0-22-generic\",\"BuildTime\":\"Wed, 20 Apr 2016 14:19:16 -0700\"}\n", 334) = 334
    
  4. Der Client ( docker version) zeigt dann die Informationen an, die der Server zurückgegeben hat:

    Server:
     Version:      1.10.3
     API version:  1.22
     Go version:   go1.6.1
     Git commit:   20f81dd
     Built:        Wed, 20 Apr 2016 14:19:16 -0700
     OS/Arch:      linux/amd64
    

In Ihrem Problem hat Ihr Docker-Daemon anscheinend Schritt 3 nicht ausgeführt, da der Client in diesem Fall die Antwort gesehen hätte, der Client jedoch nichts erhalten hat.

Anhand dieser Informationen sollten Sie herausfinden können, warum der Docker-Dämon nicht auf Anforderungen des Clients antwortet.

Mögliche Ursachen

Die von Ihnen bereitgestellten Informationen reichen nicht aus, um die Ursache für die Unfähigkeit Ihres Docker-Clients zu ermitteln, eine Antwort vom Docker-Daemon zu erhalten. Hier jedoch einige Tipps:

  • Läuft der Docker-Daemon?
  • Was passiert, wenn Sie den Docker-Daemon im Vordergrund starten ?: sudo docker daemon
  • Hört der Docker-Dämon den Socket um /var/run/docker.sock? sudo lsof -p $DOCKER_PIDsollte /var/run/docker.sock type=STREAMdort irgendwo " " anzeigen.
  • Gibt es Sicherheitsrichtlinien, die den Client oder den Daemon blockieren? Unter Linux können SELinux und AppArmor Verwirrung stiften, da für sie festgelegte Richtlinien den Zugriff verweigern können.
  • straceWenn Sie im of-Daemon keine HTTP-GET-Anforderung vom Client erhalten, bedeutet dies, dass der Server nichts vom Socket empfangen hat.
  • Wenn ja docker versionin den und zu sehen stracevon dem Dämon , dass es keine war uname()Anruf, hat der Dämon nicht einmal versuchen , Informationen über das System zu holen.
  • Wenn Sie den write()Aufruf im stracedes Dämons sehen, bedeutet dies, dass der Dämon geantwortet hat, der Client ihn jedoch nicht gesehen hat.
  • Möglicherweise ist dies ein bekanntes Problem in der älteren Version von Docker, die Sie verwenden. Versuchen Sie ein Upgrade.
Deltik
quelle
1
Für mich lag es daran, dass dockerich nur den TCP-Socket abhörte und nicht den docker.sock. Ich wurde verrückt, bis ich das verstand (danke für deine vollständige Antwort, die mir sehr hilft). Überprüfen Sie Ihre /etc/sysconfig/docker-network, um sicherzustellen, dass Sie-H unix:///var/run/docker.sock
Tag des Jüngsten Gerichts