1. 개요

이 예제에서는 Docker Engine API를 사용하여 컨테이너 내부에서 Docker 컨테이너 정보에 액세스하는 방법을 볼 것입니다.

2. 설정

여러 가지 방법으로 Docker 엔진에 연결할 수 있습니다. 우리는 Linux에서 가장 유용한 것들을 다룰 것이지만 다른 운영 체제에서도 작동합니다.

그러나, 우리는한다 매우 조심 , 원격 액세스를 가능하게하는 Security 위험을 나타 내기 때문이다 . 컨테이너가 엔진에 액세스할 수 있으면 호스트 운영 체제와의 격리가 해제됩니다 .

설정 부분의 경우 호스트를 완전히 제어할 수 있다고 간주합니다.

2.1. 기본 Unix 소켓 전달

기본적으로 Docker 엔진은 호스트 OS의 /var/run/docker.sock 아래 마운트된 Unix 소켓을 사용합니다 .

$ ss -xan | grep var

u_str LISTEN 0      4096              /var/run/docker/libnetwork/dd677ae5f81a.sock 56352            * 0           
u_dgr UNCONN 0      0                                 /var/run/chrony/chronyd.sock 24398            * 0           
u_str LISTEN 0      4096                                      /var/run/nscd/socket 23131            * 0           
u_str LISTEN 0      4096                              /var/run/docker/metrics.sock 42876            * 0           
u_str LISTEN 0      4096                                      /var/run/docker.sock 53704            * 0    
...       

이 접근 방식을 사용하면 API에 액세스할 수 있는 컨테이너를 엄격하게 제어할 수 있습니다. 이것이 Docker CLI가 배후에서 작동하는 방식입니다.

알파인 Docker 컨테이너를 시작 하고 -v 플래그를 사용하여 이 경로를 마운트하겠습니다 .

$ docker run -it -v /var/run/docker.sock:/var/run/docker.sock alpine

(alpine) $

다음으로 컨테이너에 몇 가지 유틸리티를 설치해 보겠습니다.

(alpine) $ apk add curl && apk add jq

fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/community/x86_64/APKINDEX.tar.gz
(1/4) Installing ca-certificates (20191127-r2)
(2/4) Installing nghttp2-libs (1.40.0-r1)
...

이제 curl–unix-socket 플래그Jq 와 함께 사용 하여 일부 컨테이너 데이터를 가져오고 필터링해 보겠습니다 .

(alpine) $ curl -s --unix-socket /var/run/docker.sock http://dummy/containers/json | jq '.'

[
  {
    "Id": "483c5d4aa0280ca35f0dbca59b5d2381ad1aa455ebe0cf0ca604900b47210490",
    "Names": [
      "/wizardly_chatelet"
    ],
    "Image": "alpine",
    "ImageID": "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
    "Command": "/bin/sh",
    "Created": 1595882408,
    "Ports": [],
...

여기 에서 /containers/json 엔드포인트 에서 GET실행하고 현재 실행 중인 컨테이너를 가져옵니다 . 그런 다음 jq 를 사용하여 출력을 예쁘게 만듭니다.

엔진 API에 대한 자세한 내용은 잠시 후에 다루겠습니다.

2.2. TCP 원격 액세스 활성화

TCP 소켓을 사용하여 원격 액세스를 활성화할 수도 있습니다.

systemd 와 함께 제공되는 Linux 배포의 경우 Docker 서비스 단위를 사용자 지정해야 합니다. 다른 Linux 배포판의 경우 일반적으로 /etc/docker있는 daemon.json 을 사용자 지정해야 합니다 .

대부분의 단계가 유사하므로 첫 번째 유형의 설정만 다룰 것입니다.

기본 도커 설정은 다리 네트워크를 포함 . 이다 달리 명시하지 않는 한 모든 컨테이너가 연결되는 곳 .

컨테이너만 엔진 API에 액세스할 수 있도록 허용하고 싶기 때문에 먼저 컨테이너의 네트워크를 식별해 보겠습니다.

$ docker network ls

a3b64ea758e1        bridge              bridge              local
dfad5fbfc671        host                host                local
1ee855939a2a        none                null                local

세부 정보를 살펴보겠습니다.

$ docker network inspect a3b64ea758e1

[
    {
        "Name": "bridge",
        "Id": "a3b64ea758e1f02f4692fd5105d638c05c75d573301fd4c025f38d075ed2a158",
...
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
...

다음으로 Docker 서비스 단위가 있는 위치를 보겠습니다.

$ systemctl status docker.service

docker.service - Docker Application Container Engine
     Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
...
     CGroup: /system.slice/docker.service
             ├─6425 /usr/bin/dockerd --add-runtime oci=/usr/sbin/docker-runc
             └─6452 docker-containerd --config /var/run/docker/containerd/containerd.toml --log-level warn

이제 서비스 단위 정의를 살펴보겠습니다.

$ cat /usr/lib/systemd/system/docker.service

[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.com
After=network.target lvm2-monitor.service SuSEfirewall2.service

[Service]
EnvironmentFile=/etc/sysconfig/docker
...
Type=notify
ExecStart=/usr/bin/dockerd --add-runtime oci=/usr/sbin/docker-runc $DOCKER_NETWORK_OPTIONS $DOCKER_OPTS
ExecReload=/bin/kill -s HUP $MAINPID
...

ExecStart의 어떤 명령 속성을 정의에 의해 실행되는 systemd 합니다 ( dockerd의 실행). -H 플래그를 전달하고 수신할 해당 네트워크와 포트를 지정합니다 .

이 서비스 단위를 직접 수정할 수 있지만(권장하지 않음) $DOCKER_OPTS 변수( EnvironmentFile=/etc/sysconfig/docker에 정의  됨)를 사용하겠습니다 .

$ cat /etc/sysconfig/docker 

## Path           : System/Management
## Description    : Extra cli switches for docker daemon
## Type           : string
## Default        : ""
## ServiceRestart : docker
#
DOCKER_OPTS="-H unix:///var/run/docker.sock -H tcp://172.17.0.1:2375"

여기에서는 브리지 네트워크의 게이트웨이 주소를 바인드 주소로 사용 합니다. 이것은 호스트 docker0 인터페이스에 해당합니다 .

$ ip address show dev docker0

3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:6c:7d:9c:8d brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:6cff:fe7d:9c8d/64 scope link 
       valid_lft forever preferred_lft forever

또한 Docker CLI가 호스트에서 계속 작동하도록 로컬 Unix 소켓을 활성화합니다.

한 단계 더 해야 합니다. 컨테이너 패킷이 호스트에 도달하도록 허용해 보겠습니다 .

$ iptables -I INPUT -i docker0 -j ACCEPT

여기에서는 docker0 인터페이스를 통해 들어오는 모든 패키지를 허용하도록 Linux 방화벽을 설정합니다 .

이제 Docker 서비스를 다시 시작하겠습니다.

$ systemctl restart docker.service
$ systemctl status docker.service
 docker.service - Docker Application Container Engine
     Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
...
     CGroup: /system.slice/docker.service
             ├─8110 /usr/bin/dockerd --add-runtime oci=/usr/sbin/docker-runc -H unix:///var/run/docker.sock -H tcp://172.17.0.1:2375
             └─8137 docker-containerd --config /var/run/docker/containerd/containerd.toml --log-level wa

알파인 컨테이너를 다시 실행해 보겠습니다 .

(alpine) $ curl -s http://172.17.0.1:2375/containers/json | jq '.'

[
  {
    "Id": "45f13902b710f7a5f324a7d4ec7f9b934057da4887650dc8fb4391c1d98f051c",
    "Names": [
      "/unruffled_cray"
    ],
    "Image": "alpine",
    "ImageID": "sha256:a24bb4013296f61e89ba57005a7b3e52274d8edd3ae2077d04395f806b63d83e",
    "Command": "/bin/sh",
    "Created": 1596046207,
    "Ports": [],
...

우리는해야 브릿지 네트워크에 연결된 모든 컨테이너 데몬 API에 액세스 할 수 있는지 알고 .

또한 TCP 연결은 암호화되지 않습니다 .

3. 도커 엔진 API

이제 원격 액세스를 설정했으므로 API를 살펴보겠습니다.

몇 가지 흥미로운 옵션만 살펴보겠지만 자세한 내용 전체 문서항상 확인할 수 있습니다 .

컨테이너에 대한 정보를 알아 보겠습니다 .

(alpine) $ curl -s http://172.17.0.1:2375/containers/"$(hostname)"/json | jq '.'

{
  "Id": "45f13902b710f7a5f324a7d4ec7f9b934057da4887650dc8fb4391c1d98f051c",
  "Created": "2020-07-29T18:10:07.261589135Z",
  "Path": "/bin/sh",
  "Args": [],
  "State": {
    "Status": "running",
...

여기서 /containers/{container-id}/json URL을 사용하여 컨테이너 에 대한 세부 정보를 얻습니다.

이 경우 hostname 명령을 실행 하여 container-id 를 가져옵니다 .

다음으로 Docker 데몬에서 이벤트를 수신합니다 .

(alpine) $ curl -s http://172.17.0.1:2375/events | jq '.'

이제 다른 터미널에서 hello-world 컨테이너를 시작하겠습니다 .

$ docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.
...

알파인 컨테이너로 돌아 가면 많은 이벤트가 발생합니다.

{
  "status": "create",
  "id": "abf881cbecfc0b022a3c1a6908559bb27406d0338a917fc91a77200d52a2553c",
  "from": "hello-world",
  "Type": "container",
  "Action": "create",
...
}
{
  "status": "attach",
  "id": "abf881cbecfc0b022a3c1a6908559bb27406d0338a917fc91a77200d52a2553c",
  "from": "hello-world",
  "Type": "container",
  "Action": "attach",
...

지금까지 우리는 방해가 되지 않는 일을 해왔습니다. 조금 흔들릴 시간입니다.

컨테이너를 만들고 시작합시다. 먼저 매니페스트를 정의합니다.

(alpine) $ cat > create.json << EOF
{
  "Image": "hello-world",
  "Cmd": ["/hello"]
}
EOF

이제 매니페스트를 사용하여 /containers/create 엔드포인트를 호출해 보겠습니다 .

(alpine) $ curl -X POST -H "Content-Type: application/json" -d @create.json http://172.17.0.1:2375/containers/create

{"Id":"f96a6360ad8e36271cc75a3cff05348761569cf2f089bbb30d826bd1e2d52f59","Warnings":[]}

그런 다음 id를 사용하여 컨테이너를 시작합니다.

(alpine) $ curl -X POST http://172.17.0.1:2375/containers/f96a6360ad8e36271cc75a3cff05348761569cf2f089bbb30d826bd1e2d52f59/start

마지막으로 로그를 탐색할 수 있습니다.

(alpine) $ curl http://172.17.0.1:2375/containers/f96a6360ad8e36271cc75a3cff05348761569cf2f089bbb30d826bd1e2d52f59/logs?stdout=true --output -

Hello from Docker!
KThis message shows that your installation appears to be working correctly.

;To generate this message, Docker took the following steps:
3 1. The Docker client contacted the Docker daemon.
...

각 줄의 시작 부분에 이상한 문자가 나타납니다. 이것은 로그가 전송되는 스트림이 stderrstdout 을 구별하기 위해 다중화 되기 때문에 발생합니다 .

결과적으로 출력은 추가 처리가 필요합니다.

컨테이너를 생성할 때 TTY 옵션을 활성화하면 이를 방지할 수 있습니다 .

(alpine) $ cat create.json

{
  "Tty":true,	
  "Image": "hello-world",
  "Cmd": ["/hello"]
}

4. 결론

이 예제에서는 Docker Engine Remote API를 사용하는 방법을 배웠습니다.

UNIX 소켓 또는 TCP에서 원격 액세스를 설정하는 것으로 시작하여 원격 API를 사용하는 방법을 더 자세히 보여주었습니다.

Generic footer banner