Версия докера зависает перед информацией о сервере
Вступление
Я пытаюсь использовать следующую версию 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}}{{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}}`
это продолжается в этом разделе:
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
от докера 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
повесить и как это можно починить? - Или есть более эффективный способ проверить причину этой ошибки?
1 ответ
Ваш 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
Получите идентификатор процесса вашего демона Docker. Любая из этих команд будет хранить PID в переменной с именем
$DOCKER_PID
,Прямо из розетки:
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}')
Другой:
DOCKER_PID=$(ps aux | grep 'docker daemon' | grep -v 'grep' | awk '{print $2}' | head -1)
использование
strace
на демоне Docker, теперь, когда у вас есть PID:sudo strace -vvvfts1000 -p $DOCKER_PID
В отдельном терминале выполните команду, которая обычно висит в клиенте Docker.
docker version
Смотри
strace
на демоне Docker, чтобы засвидетельствовать, что происходит, начиная со слушающего конца сокета.
Интерпретация strace
выход
Вот что демон должен делать при запуске docker version
:
Прочитайте, что отправил клиент:
[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
Соберите информацию о системе:
[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
Ответ клиенту с информацией о системе:
[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
Клиент (
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, которую вы используете. Попробуйте обновить.