3 분 소요

개요

  • 공식 문서
  • Docker 데몬(dockerd)은 HTTP RESTful API(Docker Engine API)를 통해 모든 기능을 제어
  • docker CLI 자체도 내부적으로 이 API를 사용
  • SDK(Go, Python)와 HTTP API 두 가지 방식으로 사용 가능
  • SDK는 하위 버전 호환 — API 버전 협상(WithAPIVersionNegotiation) 지원
접근 방식 설명
Unix Socket 로컬 기본 방식 — /var/run/docker.sock
TCP 원격 접속 — 별도 설정 필요 (TLS 적용 강력 권장)
Go SDK github.com/docker/docker/client — 타입 안전 API
Python SDK docker 패키지 — 스크립트·자동화에 적합


HTTP API

Unix Socket 호출

  # 이미지 목록
  curl --unix-socket /var/run/docker.sock http://localhost/v1.41/images/json

  # 컨테이너 목록 (실행 중)
  curl --unix-socket /var/run/docker.sock http://localhost/v1.41/containers/json

  # 데몬 정보
  curl --unix-socket /var/run/docker.sock http://localhost/v1.41/info

TCP 호출 (원격 접속 설정 후)

  curl -X GET http://127.0.0.1:3000/v1.41/images/json


SDK

Go SDK

  go get github.com/docker/docker/client
cli, err := client.NewClientWithOpts(
    client.FromEnv,
    client.WithAPIVersionNegotiation(),
)
  • client.FromEnv: DOCKER_HOST, DOCKER_TLS_VERIFY, DOCKER_CERT_PATH 환경변수 참조
  • 원격 접속 시: client.WithHost("tcp://127.0.0.1:3000")

Python SDK

  pip install docker
import docker
client = docker.from_env()
images = client.images.list()
for img in images:
    print(img.id)


원격 접속 설정

Docker 데몬은 기본적으로 Unix Socket만 리슨 — TCP 원격 접속을 위해 추가 설정 필요.

주의: TCP를 평문으로 열면 보안 위험이 있습니다. 운영 환경에서는 반드시 TLS 인증서를 적용하세요.

systemd 서비스 수정

  # /lib/systemd/system/docker.service
  ExecStart=/usr/bin/dockerd \
    -H fd:// \
    --containerd=/run/containerd/containerd.sock \
    -H tcp://0.0.0.0:3000

  systemctl daemon-reload
  systemctl restart docker

daemon.json 으로 설정 (권장)

  # /etc/docker/daemon.json
  {
    "hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:3000"]
  }

  # 단, systemd 서비스의 -H 옵션과 중복 설정 시 충돌 주의
  # /lib/systemd/system/docker.service 에서 -H fd:// 제거 필요

TLS 원격 접속 (권장)

  # 클라이언트 환경변수 설정
  export DOCKER_HOST=tcp://<server-ip>:2376
  export DOCKER_TLS_VERIFY=1
  export DOCKER_CERT_PATH=~/.docker/certs


주요 API 엔드포인트

리소스 메서드 경로 설명
이미지 GET /images/json 이미지 목록
이미지 POST /images/create 이미지 pull
이미지 DELETE /images/{name} 이미지 삭제
컨테이너 GET /containers/json 컨테이너 목록
컨테이너 POST /containers/create 컨테이너 생성
컨테이너 POST /containers/{id}/start 컨테이너 시작
컨테이너 POST /containers/{id}/stop 컨테이너 중지
컨테이너 POST /containers/{id}/wait 컨테이너 상태 대기
컨테이너 GET /containers/{id}/logs 컨테이너 로그
컨테이너 DELETE /containers/{id} 컨테이너 삭제
볼륨 GET /volumes 볼륨 목록
네트워크 GET /networks 네트워크 목록
시스템 GET /info 데몬 정보
시스템 GET /version API 버전 정보


예제

이미지 목록 조회

HTTP

  curl -X GET http://127.0.0.1:3000/v1.41/images/json

Go SDK

package main

import (
    "context"
    "fmt"

    "github.com/docker/docker/api/types/image"
    "github.com/docker/docker/client"
)

func main() {
    ctx := context.Background()
    cli, err := client.NewClientWithOpts(
        client.WithHost("tcp://127.0.0.1:3000"),
        client.WithAPIVersionNegotiation(),
    )
    if err != nil {
        panic(err)
    }
    defer cli.Close()

    images, err := cli.ImageList(ctx, image.ListOptions{})
    if err != nil {
        panic(err)
    }

    for _, img := range images {
        fmt.Println(img.ID)
    }
}

컨테이너 생성·실행·로그·삭제

HTTP

# 1. 이미지 pull
curl -X POST "http://127.0.0.1:3000/v1.41/images/create?fromImage=alpine:3.16.0"

# 2. 컨테이너 생성 → 응답 예: {"Id":"ac6594faf5","Warnings":[]}
curl -H "Content-Type: application/json" \
     -d '{"Image": "alpine:3.16.0", "Cmd": ["echo", "hello world"]}' \
     -X POST http://127.0.0.1:3000/v1.41/containers/create

# 3. 컨테이너 시작
curl -X POST http://127.0.0.1:3000/v1.41/containers/ac6594faf5/start

# 4. 종료 대기
curl -X POST "http://127.0.0.1:3000/v1.41/containers/ac6594faf5/wait?condition=not-running"

# 5. 로그 확인
curl -X GET "http://127.0.0.1:3000/v1.41/containers/ac6594faf5/logs?stdout=1"

# 6. 컨테이너 삭제
curl -X DELETE http://127.0.0.1:3000/v1.41/containers/ac6594faf5

Go SDK

package main

import (
    "context"
    "io"
    "os"

    "github.com/docker/docker/api/types/container"
    "github.com/docker/docker/api/types/image"
    "github.com/docker/docker/client"
    "github.com/docker/docker/pkg/stdcopy"
)

func main() {
    ctx := context.Background()
    cli, err := client.NewClientWithOpts(
        client.WithHost("tcp://127.0.0.1:3000"),
        client.WithAPIVersionNegotiation(),
    )
    if err != nil {
        panic(err)
    }
    defer cli.Close()

    // 1. 이미지 pull
    rc, err := cli.ImagePull(ctx, "alpine:3.16.0", image.PullOptions{})
    if err != nil {
        panic(err)
    }
    defer rc.Close()
    io.Copy(os.Stdout, rc)

    // 2. 컨테이너 생성
    resp, err := cli.ContainerCreate(ctx, &container.Config{
        Image: "alpine:3.16.0",
        Cmd:   []string{"echo", "hello world"},
    }, nil, nil, nil, "")
    if err != nil {
        panic(err)
    }

    // 3. 컨테이너 시작
    if err := cli.ContainerStart(ctx, resp.ID, container.StartOptions{}); err != nil {
        panic(err)
    }

    // 4. 종료 대기
    statusCh, errCh := cli.ContainerWait(ctx, resp.ID, container.WaitConditionNotRunning)
    select {
    case err := <-errCh:
        if err != nil {
            panic(err)
        }
    case <-statusCh:
    }

    // 5. 로그 출력
    logRC, err := cli.ContainerLogs(ctx, resp.ID, container.LogsOptions{ShowStdout: true})
    if err != nil {
        panic(err)
    }
    stdcopy.StdCopy(os.Stdout, os.Stderr, logRC)

    // 6. 컨테이너 삭제
    if err := cli.ContainerRemove(ctx, resp.ID, container.RemoveOptions{}); err != nil {
        panic(err)
    }
}


관련 포스트