💡

dockerコマンドを通してlinuxのsocket通信を確認

に公開

GOAL

dockerCLIとdockerdとのソケット通信を確認してみます。

環境

EC2を立ち上げ、ssmで接続して確認していきます。
例:↓↓↓↓

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"

  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "${local.env}-main-vpc"
  }
}

resource "aws_subnet" "public-1a" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "ap-northeast-1a"
  map_public_ip_on_launch = true

  tags = {
    Name = "${local.env}-public-subnet-1a"
  }
}

resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "${local.env}-main-igw"
  }
}

resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.main.id
  }

  tags = {
    Name = "${local.env}-public-route-table"
  }
}

resource "aws_route_table_association" "public_association_1a" {
  subnet_id      = aws_subnet.public-1a.id
  route_table_id = aws_route_table.public.id
}

resource "aws_security_group" "app_instance" {
  vpc_id = aws_vpc.main.id

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "${local.env}-app-instance-security-group"
  }
}

resource "aws_instance" "app" {
  ami                    = "ami-03d25459ad01ac2b9"
  instance_type          = "t3.micro"
  subnet_id              = aws_subnet.public-1a.id
  vpc_security_group_ids = [aws_security_group.app_instance.id]
  user_data              = templatefile("./user_data.sh", {})
  iam_instance_profile   = aws_iam_instance_profile.ssm_profile.name

  metadata_options {
    http_tokens = "required"
  }

  tags = {
    Name = "${local.env}-public-instance"
  }
}

resource "aws_iam_role" "ssm_role" {
  name = "ssm-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [{
      Effect = "Allow",
      Principal = {
        Service = "ec2.amazonaws.com"
      },
      Action = "sts:AssumeRole"
    }]
  })
}

resource "aws_iam_role_policy_attachment" "ssm_attach" {
  role       = aws_iam_role.ssm_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}

resource "aws_iam_instance_profile" "ssm_profile" {
  name = "ssm-profile"
  role = aws_iam_role.ssm_role.name
}

dockerコマンドを実行すると起きること

docker ps や docker run のようなコマンドを実行すると、実際には以下の流れで処理が進みます:

  1. Docker CLI(docker バイナリ) が起動し、引数をパースします。
  2. CLI は UNIXドメインソケット /var/run/docker.sock を通じて、
  3. dockerd(Dockerデーモン)に HTTP リクエスト を送信します。
  4. dockerd はこのリクエストを処理し、必要に応じてコンテナを作成・停止・情報を返却などを行います。
  5. 結果が CLI に戻り、整形された人間向けの出力として表示されます。

Docker CLIがUNIXドメインソケットを介して通信されることを確認

ssm-userでログインしている状態で、docker version を実行するとclientの情報は返却されます。 が、socketに接続する権限が無いことがレスポンスされます。

sh-4.2$ docker version
Client:
 Version:           25.0.8
 API version:       1.44
 Go version:        go1.23.8
 Git commit:        0bab007
 Built:             Fri May 16 16:25:26 2025
 OS/Arch:           linux/amd64
 Context:           default

permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.44/version": dial unix /var/run/docker.sock: connect: permission denied

権限を確認すると、rootかdocker groupでwriteが実行できるようです。

ls -la /var/run/docker.sock
srw-rw---- 1 root docker 0 Jun  7 04:21 /var/run/docker.sock

rootで実行するとserverの情報も返ってきました。

sh-4.2$ sudo docker version
Client:
 Version:           25.0.8
 API version:       1.44
 Go version:        go1.23.8
 Git commit:        0bab007
 Built:             Fri May 16 16:25:26 2025
 OS/Arch:           linux/amd64
 Context:           default

Server:
 Engine:
  Version:          25.0.8
  API version:      1.44 (minimum version 1.24)
  Go version:       go1.23.8
  Git commit:       71907ca
  Built:            Fri May 16 16:25:56 2025
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.7.27
  GitCommit:        05044ec0a9a75232cad458027ca83437aae3f4da
 runc:
  Version:          1.2.4
  GitCommit:        6c52b3fc541fb26fe8c374d5f58112a0a5dbda66
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

linuxのシステムコールを追跡

sh-4.2$ sudo strace -f -e trace=network docker version
strace: Process 9760 attached
strace: Process 9761 attached
strace: Process 9762 attached
strace: Process 9763 attached
strace: Process 9764 attached
[pid  9759] socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
[pid  9759] connect(3, {sa_family=AF_UNIX, sun_path="/var/run/docker.sock"}, 23) = 0
[pid  9759] getsockname(3, {sa_family=AF_UNIX}, [112->2]) = 0
[pid  9759] getpeername(3, {sa_family=AF_UNIX, sun_path="/run/docker.sock"}, [112->19]) = 0
Client:
 Version:           25.0.8
 API version:       1.44
 Go version:        go1.23.8
 Git commit:        0bab007
 Built:             Fri May 16 16:25:26 2025
 OS/Arch:           linux/amd64
 Context:           default

Server:
 Engine:
  Version:          25.0.8
  API version:      1.44 (minimum version 1.24)
  Go version:       go1.23.8
  Git commit:       71907ca
  Built:            Fri May 16 16:25:56 2025
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.7.27
  GitCommit:        05044ec0a9a75232cad458027ca83437aae3f4da
 runc:
  Version:          1.2.4
  GitCommit:        6c52b3fc541fb26fe8c374d5f58112a0a5dbda66
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
[pid  9762] +++ exited with 0 +++
[pid  9764] +++ exited with 0 +++
[pid  9763] +++ exited with 0 +++
[pid  9760] +++ exited with 0 +++
[pid  9761] +++ exited with 0 +++
+++ exited with 0 +++

[pid 9759] connect(3, {sa_family=AF_UNIX, sun_path="/var/run/docker.sock"}, 23) = 0

/var/run/docker.sockに接続して、docker psの結果を出力しています。

dockerコマンドの実態

docker cliはUNIXドメインソケットへのリクエストの詳細を確認してみます。

socketへのHTTPリクエスト

socketへのリクエストはHTTPリクエストが行われています。
実際にシステムコールを通して確認してみます。

sh-4.2$ sudo strace -f -e trace=read,write,connect -s 4096 docker version 2>&1 | grep -E 'GET|POST|HEAD|PUT|DELETE|HTTP/1\.[01]'
[pid  9781] write(3, "HEAD /_ping HTTP/1.1\r\nHost: api.moby.localhost\r\nUser-Agent: Docker-Client/25.0.8 (linux)\r\n\r\n", 92) = 92
[pid  9781] read(3, "HTTP/1.1 200 OK\r\nApi-Version: 1.44\r\nBuilder-Version: 2\r\nCache-Control: no-cache, no-store, must-revalidate\r\nContent-Length: 0\r\nContent-Type: text/plain; charset=utf-8\r\nDocker-Experimental: false\r\nOstype: linux\r\nPragma: no-cache\r\nServer: Docker/25.0.8 (linux)\r\nSwarm: inactive\r\nDate: Sat, 07 Jun 2025 05:04:14 GMT\r\n\r\n", 4096) = 316
[pid  9781] write(3, "GET /v1.44/version HTTP/1.1\r\nHost: api.moby.localhost\r\nUser-Agent: Docker-Client/25.0.8 (linux)\r\n\r\n", 99) = 99
[pid  9781] read(3, "HTTP/1.1 200 OK\r\nApi-Version: 1.44\r\nContent-Type: application/json\r\nDocker-Experimental: false\r\nOstype: linux\r\nServer: Docker/25.0.8 (linux)\r\nDate: Sat, 07 Jun 2025 05:04:14 GMT\r\nContent-Length: 844\r\n\r\n{\"Platform\":{\"Name\":\"\"},\"Components\":[{\"Name\":\"Engine\",\"Version\":\"25.0.8\",\"Details\":{\"ApiVersion\":\"1.44\",\"Arch\":\"amd64\",\"BuildTime\":\"2025-05-16T16:25:56.000000000+00:00\",\"Experimental\":\"false\",\"GitCommit\":\"71907ca\",\"GoVersion\":\"go1.23.8\",\"KernelVersion\":\"5.10.220-209.869.amzn2.x86_64\",\"MinAPIVersion\":\"1.24\",\"Os\":\"linux\"}},{\"Name\":\"containerd\",\"Version\":\"1.7.27\",\"Details\":{\"GitCommit\":\"05044ec0a9a75232cad458027ca83437aae3f4da\"}},{\"Name\":\"runc\",\"Version\":\"1.2.4\",\"Details\":{\"GitCommit\":\"6c52b3fc541fb26fe8c374d5f58112a0a5dbda66\"}},{\"Name\":\"docker-init\",\"Version\":\"0.19.0\",\"Details\":{\"GitCommit\":\"de40ad0\"}}],\"Version\":\"25.0.8\",\"ApiVersion\":\"1.44\",\"MinAPIVersion\":\"1.24\",\"GitCommit\":\"71907ca\",\"GoVersion\":\"go1.23.8\",\"Os\":\"linux\",\"Arch\":\"amd64\",\"KernelVersion\":\"5.10.220-209.869.amzn2.x86_64\",\"BuildTime\":\"2025-05-16T16:25:56.000000000+00:00\"}\n", 4096) = 1046

write(3, "GET /v1.44/version HTTP/1.1\r\nHost: api.moby.localhost\r\nUser-Agent: Docker-Client/25.0.8 (linux)\r\n\r\n", 99) = 99

ポイントはこちらです。
GET /v1.44/version HTTP/1.1 というGETリクエストを行っています。
つまり、socketのpathに対してHTTPリクエストを行っています。

dockerコマンドを介さずにsocket通信

docker cliを介さずにsocketに対して、リクエストをしてみたいと思います。

path: /var/run/docker.sock
request: v1.44/version

sh-4.2$ sudo curl --unix-socket /var/run/docker.sock http://localhost/v1.44/version
{"Platform":{"Name":""},"Components":[{"Name":"Engine","Version":"25.0.8","Details":{"ApiVersion":"1.44","Arch":"amd64","BuildTime":"2025-05-16T16:25:56.000000000+00:00","Experimental":"false","GitCommit":"71907ca","GoVersion":"go1.23.8","KernelVersion":"5.10.220-209.869.amzn2.x86_64","MinAPIVersion":"1.24","Os":"linux"}},{"Name":"containerd","Version":"1.7.27","Details":{"GitCommit":"05044ec0a9a75232cad458027ca83437aae3f4da"}},{"Name":"runc","Version":"1.2.4","Details":{"GitCommit":"6c52b3fc541fb26fe8c374d5f58112a0a5dbda66"}},{"Name":"docker-init","Version":"0.19.0","Details":{"GitCommit":"de40ad0"}}],"Version":"25.0.8","ApiVersion":"1.44","MinAPIVersion":"1.24","GitCommit":"71907ca","GoVersion":"go1.23.8","Os":"linux","Arch":"amd64","KernelVersion":"5.10.220-209.869.amzn2.x86_64","BuildTime":"2025-05-16T16:25:56.000000000+00:00"}

docker versionと同等の結果が返ってきました。

socketへのリクエストは誰が捌いているのか

ソケットファイルに対してリッスンしているプロセスを確認します。
dockerdが待機していることが分かります。dockerdがソケットに来たリクエストを捌きます。

sudo lsof -U | grep docker.sock
systemd      1           root   80u  unix 0xffff9ba943a3a000      0t0  39463 /run/docker.sock
dockerd   9107           root    4u  unix 0xffff9ba943a3a000      0t0  39463 /run/docker.sock

Discussion