версия докера зависает перед информацией о сервере

1177
karobar

Вступление

Я пытаюсь использовать следующую версию dockerна виртуальной машине Linux ( uname -aвозвращается Linux xen 4.1.17-yocto-standard #1 SMP PREEMPT Thu Jun 2 13:29:47 PDT 2016 x86_64 GNU/Linux), созданный по docker_gitрецепту BitBake .

Если я пытаюсь запустить docker version, я получаю следующий вывод:

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 

Затем команда зависает.

Как это должно выглядеть

Я попытался выполнить docker versionна работающей установке Docker (Ubuntu 14.04), и я получаю следующий вывод:

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 

Итак, я предполагаю, что есть какая-то ошибка при получении информации о сервере.

Дополнительные исследования

Я не знаком с Go, так что этот раздел может вызывать недовольство, когда я пытаюсь понять, что здесь происходит.

Я начал смотреть на эту часть api/client/version.goисходного кода Docker:

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}}{} Experimental: {{.Client.Experimental}}{}{} 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}}{} Experimental: {{.Server.Experimental}}{}{}` 

это продолжается в этом разделе:

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(), }, } 

От engine-api/types/client.go:

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

Таким образом, все, что нужно сделать на этом этапе, это назначить что-то Serverчлену (типа *Version). Это происходит в разделе после vdназначения сверху:

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

Определение функции для ServerVersionследующегоengine-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 } 

Из того, что я могу собрать, выше getточку вызова функции client/request.goиз Docker в engine APIрепо

// 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) } 

Куда:

  • ctx является context.Background()
  • path является /version
  • нет query
  • нет headers

И эта документация для sendRequestот 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 } 

Некоторое время это была догадка, и теперь я обеспокоен тем, что могу искать не в том месте.

Вопросы

  • Что вызывает docker version, docker run hello-world, docker images, docker ps, и docker infoповесить и как это исправить?
  • Или есть более эффективный способ проверить причину этой ошибки?
3
Какая ОС у вас работает? Вы пытались установить более новую версию докера? Ken J 7 лет назад 0
Это очень специфический вопрос, касающийся очень специфического проекта, который меня просто поразил: `Этот пакет содержит демон и клиент. Использование docker.io на хостах, отличных от amd64, в настоящее время не поддерживается. Вы уверены, что используете его на процессоре AMD, а не на Intel? Vojtěch Dohnal 7 лет назад 0
Я работал на виртуальном процессоре Intel. Кроме того, на вопрос Кена, ОС является доморощенной с ядром linux 4.1. Я также пытался установить 1.11 с похожими эффектами. Я скоро обновлю вопрос. karobar 7 лет назад 0
Вы должны `связать` процесс / демон, который слушает сокет в` / var / run / docker.sock`. Ваша команда `docker info` отправила запрос, начинающийся с" GET /v1.18/info HTTP / 1.1 \ r \ nHost: ", в сокет и ожидала ответа вечно, но сервер не ответил. Deltik 7 лет назад 0

1 ответ на вопрос

3
Deltik

Ваш straceвывод настоятельно предполагает, что клиент Docker не может общаться с демоном Docker, который по умолчанию создает сокет в /var/run/docker.sock.

Предполагается, что Docker-демон является системной службой (в systemd, расположенной по адресу /lib/systemd/system/docker.serviceс конфигурацией сокета в /lib/systemd/system/docker.socket), но его можно запустить независимо, используя /usr/bin/docker daemonлюбые дополнительные опции.

Вы должны демон, а не клиента .strace

Использование straceна демоне Docker

  1. Получите идентификатор процесса вашего демона Docker. Любая из этих команд будет хранить PID в переменной с именем $DOCKER_PID.

    • Прямо из розетки:

      DOCKER_PID=$(sudo lsof -Ua /var/run/docker.sock | awk '/^docker/ ' | head -1) 
    • Systemd:

      DOCKER_PID=$(systemctl show -p MainPID docker.service | awk -F'=' '') 
    • Другой:

      DOCKER_PID=$(ps aux | grep 'docker daemon' | grep -v 'grep' | awk '' | head -1) 
  2. Используйте straceна демоне Docker, теперь, когда у вас есть PID:

    sudo strace -vvvfts1000 -p $DOCKER_PID 
  3. В отдельном терминале выполните команду, которая обычно висит в клиенте Docker.

    docker version 
  4. Посмотрите straceна демона Docker, чтобы увидеть, что происходит, начиная со слушающего конца сокета.

Интерпретация straceвывода

Вот что демон должен делать при запуске docker version:

  1. Прочитайте, что отправил клиент:

    [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. Соберите информацию о системе:

    [pid 14291] 12:34:36 uname() = 0 
  3. Ответ клиенту с информацией о системе:

    [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. Затем client ( docker version) отображает информацию, которую вернул сервер:

    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 

В вашей задаче ваш демон Docker, по-видимому, не выполнил шаг № 3, потому что если бы он это сделал, клиент увидел бы ответ, но клиент ничего не получил.

Вы должны быть в состоянии использовать эту информацию, чтобы выяснить, почему демон Docker не отвечает на запросы от клиента.

Возможные причины

Предоставленной вами информации недостаточно для точного определения причины неспособности вашего клиента Docker получить ответ от демона Docker, но вот несколько советов:

  • Работает ли демон Docker?
  • Что произойдет, если вы запустите демон Docker на переднем плане ?: sudo docker daemon
  • Демон Docker слушает сокет в /var/run/docker.sock? sudo lsof -p $DOCKER_PIDдолжен показать " /var/run/docker.sock type=STREAM" там где-то.
  • Существуют ли политики безопасности, которые блокировали бы что-то в клиенте или демоне? В Linux SELinux и AppArmor могут вызвать путаницу, так как установленные для них политики могут запретить доступ.
  • В straceдемоне, если вы не получаете HTTP GET-запрос от клиента, это означает, что сервер ничего не получил из сокета.
  • Если вы это сделали docker versionи увидели в straceдемоне, что uname()вызова не было, демон даже не попытался получить информацию о системе.
  • Если вы видите write()вызов в straceдемоне, это означает, что демон ответил, но клиент его не увидел.
  • Возможно, это известная проблема в старой версии Docker, которую вы используете. Попробуйте обновить.
Для меня это было потому, что `docker` слушал только по TCP-сокету, а не по docker.sock. Я сходил с ума, пока не понял этого (спасибо за ваш полный ответ, который мне очень помог). Дважды проверьте `/ etc / sysconfig / docker-network`, чтобы убедиться, что у вас есть` -H unix: /// var / run / docker.sock` Doomsday 7 лет назад 1

Похожие вопросы