파이썬 기반 docker 라이브러리 정리
1. 설치 및 초기화
1) 설치
pip install docker
2) 클라이언트 초기화
1. docker.from_env()
- 환경 변수에서 Docker 설정을 자동으로 가져와 클라이언트를 생성한다.
- 내부적으로 DockerClient 객체를 반환한다.
- Docker 데몬과 연결할 수 있도록 환경 변수를 자동 감지한다.
- 일반적으로 로컬 개발 환경에서 사용된다.
2. docker.DockerClient(...)
- Docker 데몬과의 직접적인 연결을 설정한다.
- DockerClient 클래스의 인스턴스를 직접 생성하여 사용자가 원하는 설정을 지정할 수 있다.
import docker
# 기본 초기화 (로컬 Docker 데몬 연결)
client = docker.from_env()
# 고급 옵션 (TLS 인증, 원격 호스트)
client = docker.DockerClient(
base_url='tcp://192.168.0.10:2376',
tls=docker.tls.TLSConfig(
ca_cert='ca.pem',
client_cert=('cert.pem', 'key.pem'),
verify=True
)
)
3. docker.DockerClient의 옵션
- base_url='unix://var/run/docker.sock':
- Unix 소켓을 사용하여 로컬 Docker 데몬과 통신한다.
- Windows에서는 npipe:////./pipe/docker_engine을 사용해야 한다.
- version='auto':
- 현재 사용 가능한 Docker API 버전을 자동으로 감지한다.
- tls=False:
- TLS 보안 연결을 사용하지 않도록 설정한다.
- 원격 Docker 데몬과 통신하려면 tls=True로 설정하고 TLSConfig 객체를 제공해야 한다.
옵션명 | 타입 | 설명 |
base_url | str | Docker 데몬의 URL을 지정합니다. 기본적으로 unix://var/run/docker.sock(Linux/macOS) 또는 npipe:////./pipe/docker_engine(Windows) 사용 |
version | str 또는 float | 사용할 Docker API 버전을 지정합니다. "auto"로 설정하면 자동으로 감지됨 |
timeout | int | 요청의 타임아웃(초 단위)을 설정합니다. 기본값은 60초 |
tls | bool 또는 TLSConfig | TLS 보안 연결을 사용할지 여부 (기본값: False) |
user_agent | str | 클라이언트의 User-Agent 값을 설정 |
credstore_env | dict | 사용자 인증 정보를 저장하는 환경 변수 전달 |
2. 명령어 레퍼런스
1) 공통 명령어 (Common Commands)
1. run: 컨테이너 생성 및 실행
옵션 | 설명 | 예제 |
detach=True | 컨테이너를 백그라운드(분리 모드)로 실행 | detach=True |
remove=True | 컨테이너 종료 후 자동 삭제 | remove=True |
ports | 호스트와 컨테이너 간 포트 매핑 | {"80/tcp": 8080} |
volumes | 호스트와 컨테이너 간 볼륨 매핑 | {"host/path": {"bind": "/container/path", "mode": "rw"}} |
environment | 컨테이너 환경변수 설정 | {"ENV_VAR": "value"} |
name | 컨테이너 이름 지정 | "my_container" |
container = client.containers.run(
image="ubuntu:latest",
command="echo Hello, World",
detach=True, # 백그라운드 실행
environment={"ENV_VAR": "value"},
ports={'8080/tcp': 80}, # 호스트:컨테이너 포트 바인딩
volumes={'/host/path': {'bind': '/container/path', 'mode': 'rw'}},
name="my-container",
network="my-network"
)
2. exec: 실행 중인 컨테이너에 명령어 전달
exec_output = container.exec_run("ls -l", workdir="/app")
print(exec_output.output.decode())
3. pull(image, tag=None, stream=False, decode=False): 원격 레지스트리에서 이미지를 가져오기
ubuntu_image = client.images.pull("ubuntu", tag="latest")
4. build: Dockerfile로 이미지 빌드
image, build_logs = client.images.build(
path=".", dockerfile="Dockerfile", tag="my_image:latest",
buildargs={"MY_ARG": "value"}, decode=True
)
for chunk in build_logs:
if 'stream' in chunk:
print(chunk['stream'].strip())
image, build_logs = client.images.build(
path=".", # Dockerfile 경로
tag="my-image:1.0",
buildargs={"BUILD_ENV": "production"},
rm=True # 빌드 후 중간 컨테이너 삭제
)
for line in build_logs:
print(line.get('stream', ''))
5. list(): 로컬에 있는 모든 이미지를 리스트로 반환
images = client.images.list()
for image in images:
print(image.tags)
6. remove(image, force=False, noprune=False): 지정한 이미지를 삭제
client.images.remove("my_image:latest", force=True)
7. get(container_id_or_name): 특정 컨테이너 객체를 반환
container = client.containers.get("my_container")
8. stop(): 컨테이너를 중지
container.stop()
9. logs(stream=False, tail='all'): 컨테이너의 로그를 반환
logs = container.logs().decode('utf-8')
10. exec_run(cmd, stdout=True, stderr=True, tty=False): 실행 중인 컨테이너 내부에서 명령어를 실행
exit_code, output = container.exec_run("echo '고급 실행 예제'")
print(output.decode('utf-8'))
11. container.pause(): 현재 실행 중인 컨테이너를 일시 중지한다.
import docker
client = docker.from_env()
container = client.containers.get("container_name_or_id")
container.pause()
12. container.unpause(): 일시 중지된 컨테이너를 다시 실행한다.
if container.status == "paused":
container.unpause()
13. container.wait(timeout=None): 컨테이너가 종료될 때까지 기다리고, 종료 코드를 반환한다.
- timeout 값을 설정하면 해당 시간이 초과될 경우 예외가 발생할 수 있다.
import docker
client = docker.from_env()
container = client.containers.run("ubuntu", "sleep 5", detach=True)
# 컨테이너가 종료될 때까지 기다림
result = container.wait()
print(result) # {'StatusCode': 0}
2) 관리 명령어 (Management Commands)
1. DockerClient.networks를 통한 네트워크 관리
- client.networks.create() 메서드:
- 이 메서드는 Docker에서 새로운 네트워크를 생성하는 데 사용됩니다. 기본적으로 브리지(bridge) 네트워크를 만들며, 컨테이너 간의 통신을 설정할 수 있다.
network = client.networks.create("my_bridge", driver="bridge")
# 네트워크 생성
network = client.networks.create(
"my-network",
driver="bridge",
labels={"project": "my-app"}
)
# 네트워크에 컨테이너 연결
container.connect(network="my-network")
- 사용 가능한 옵션
옵션 | 타입 | 설명 |
name | str | 생성할 네트워크의 이름 |
driver | str | 사용할 네트워크 드라이버 (예: "bridge", "overlay", "macvlan") |
options | dict | 특정 네트워크 드라이버의 추가 옵션 (예: {"com.docker.network.bridge.enable_icc": "true"}) |
ipam | IPAMPool | IP 주소 관리(IPAM) 설정을 정의하는 객체 |
check_duplicate | bool | 같은 이름의 네트워크가 있을 경우 중복을 방지 |
internal | bool | True일 경우, 외부 네트워크에서 접근 불가 |
attachable | bool | True일 경우, 개별 컨테이너가 네트워크에 직접 연결 가능 |
ingress | bool | True일 경우, ingress 네트워크로 설정 (Swarm에서 사용) |
enable_ipv6 | bool | True일 경우, IPv6 지원 활성화 |
labels | dict | 네트워크에 부착할 라벨 지정 (예: {"project": "my-app"}) |
scope | str | 네트워크의 범위 설정 ("local", "global" 등) |
config_from | dict | 기존 네트워크 설정을 참조 (예: {"Network": "existing-network"}) |
config_only | bool | True일 경우, 네트워크를 구성 전용(config-only)으로 설정 |
driver_opts | dict | 네트워크 드라이버에 전달할 옵션 (예: {"com.docker.network.bridge.name": "my_custom_bridge"}) |
- get(network_id, …):
- 네트워크 ID를 사용하여 특정 네트워크 객체를 가져온다.
network = client.networks.get("abcdef123456")
- 사용 가능한 옵션
매개변수 | 자료형 | 설명 | 기본값/필수 여부 |
network_id | str | 검색할 네트워크의 고유 ID입니다. | 필수 |
verbose | bool | 스웜(Swarm) 모드 사용 시, 클러스터 내 서비스의 세부 정보를 포함하여 자세한 정보를 가져옵니다. | 선택사항 (명시하지 않으면 기본값 사용) |
scope | str | 네트워크를 특정 범위로 필터링합니다. 예를 들어, "swarm", "global", "local"과 같이 지정할 수 있습니다. | 선택사항 |
- list(…):
- Docker 서버에 존재하는 네트워크 목록을 조회한다.
networks = client.networks.list(filters={"driver": "bridge"})
- 사용 가능한 옵션
매개변수 | 자료형 | 설명 | 기본값/필수 여부 |
names | list | 조회할 네트워크의 이름 목록을 지정합니다. 지정된 이름과 일치하는 네트워크만 반환합니다. | 선택사항 |
ids | list | 조회할 네트워크의 ID 목록을 지정합니다. 지정된 ID와 일치하는 네트워크만 반환합니다. | 선택사항 |
filters | dict | 추가 필터 조건을 딕셔너리 형태로 지정합니다. 예를 들어, {"driver": "bridge"}와 같이 드라이버, 라벨, 유형 등으로 필터링할 수 있습니다. | 선택사항 |
greedy | bool | 각 네트워크에 대해 더 상세한 정보를 개별적으로 조회할지 여부를 결정합니다. (예: 네트워크에 연결된 컨테이너 정보 등) | 선택사항 (일반적으로 False) |
- prune(filters=None):
- 사용되지 않는(오래된 혹은 사용 중이지 않은) 네트워크를 일괄 삭제한다.
result = client.networks.prune(filters={"label": "temp_network"})
- 사용 가능한 옵션
매개변수 | 자료형 | 설명 | 기본값/필수 여부 |
filters | dict | 삭제할 네트워크를 선택하기 위한 필터 옵션입니다. 예를 들어, {"label": "temp_network"}는 라벨이 "temp_network"인 네트워크만 대상으로 합니다. | 선택사항 (기본값: None) |
2. Network 객체의 인스턴스 메소드
- client.networks.create() 메서드:
- 해당 네트워크에 컨테이너를 연결한다.
network.connect(container="my_container", aliases=["web"])
- 사용 가능한 옵션
옵션 | 타입 | 설명 |
network | str | 연결할 네트워크의 이름 또는 ID |
aliases | list | 컨테이너에 대한 네트워크 별칭 지정 |
links | list | 연결된 컨테이너와 직접 링크 설정 (링크 기능은 legacy 방식) |
ipv4_address | str | 지정된 네트워크에서 사용할 IPv4 주소 |
ipv6_address | str | 지정된 네트워크에서 사용할 IPv6 주소 |
link_local_ips | list | 컨테이너에 할당할 링크 로컬 주소 |
priority | int | 네트워크 연결 우선순위 (Swarm에서 사용) |
endpoint_config | dict | 컨테이너의 네트워크 엔드포인트 설정 (예: MAC 주소, 포트 매핑 등) |
driver_opt | dict | 네트워크 드라이버에 전달할 추가 옵션 |
container | str 또는 Container 객체 | 연결할 컨테이너 (컨테이너 ID, 이름 또는 Container 객체) |
- reload():
- Docker 서버에서 최신 네트워크 정보를 다시 불러와 내부 속성(attrs)을 갱신한다.
# 예시: 네트워크 객체의 최신 정보를 갱신
network = client.networks.get("abcdef123456")
network.reload() # 서버에서 최신 상태로 정보를 갱신
- remove():
- 네트워크를 삭제한다.
# 네트워크 객체를 가져와 삭제하는 예시
network = client.networks.get("abcdef123456")
network.remove() # 해당 네트워크를 삭제합니다.
3. 네트워크 관련 추가 구성
3.1 create_networking_config(endpoints_config):
- 여러 네트워크 연결 구성을 포함하는 네트워킹 설정을 생성한다. 각 네트워크에 연결할 엔드포인트(endpoint) 설정 정보를 포함하는 딕셔너리인 endpoints_config를 입력받아, Docker 엔진 API에 전달할 수 있는 네트워킹 구성 객체를 생성한다.
- 주요 기능 및 사용 용도
- 네트워킹 구성 생성:
- 컨테이너를 생성할 때 여러 네트워크에 동시에 연결할 수 있도록 각 네트워크별 엔드포인트 설정(예: 별칭, IP 주소 등)을 정의하여 하나의 NetworkingConfig 객체로 결합한다.
- 컨테이너 생성 시 활용:
- 생성된 네트워킹 구성은 client.create_container() 등 컨테이너 생성 메소드의 networking_config 인자로 전달되어, 컨테이너가 지정된 네트워크들에 올바르게 연결되도록 한다.
- 유연한 네트워크 설정:
- 각 네트워크에 대해 별도의 설정(예: Aliases, Links, IPAMConfig 등)을 지정할 수 있어, 복잡한 네트워크 토폴로지 구성 시 유용하게 사용된다.
# 예시: 두 개의 네트워크(기본 'bridge'와 사용자 정의 네트워크 'custom_net')에 대해 엔드포인트 설정을 구성하는 경우
endpoints_config = {
"bridge": {
"Aliases": ["mycontainer_bridge"],
"IPAMConfig": {"IPv4Address": "172.17.0.5"}
},
"custom_net": {
"Aliases": ["mycontainer_custom"],
"Links": ["other_container:alias"],
"IPAMConfig": {"IPv4Address": "192.168.1.100"}
}
}
# 네트워킹 구성 객체 생성
networking_config = client.create_networking_config(endpoints_config)
# 생성된 networking_config 객체를 컨테이너 생성 시에 전달하여,
# 컨테이너가 두 네트워크에 동시에 연결되도록 할 수 있습니다.
container = client.create_container(
image="your-image",
name="my_container",
networking_config=networking_config
)
- 매개변수 정보
매개변수 | 자료형 | 설명 |
endpoints_config | dict | 각 네트워크 이름을 키로, 해당 네트워크에 연결할 엔드포인트 설정을 값으로 갖는 딕셔너리입니다. 엔드포인트 설정은 다음과 같은 옵션들을 포함할 수 있다. 예시 옵션: - Aliases: 해당 네트워크 내에서 사용할 별칭 목록 (리스트 형태) - Links: 연결할 다른 컨테이너에 대한 링크 정보 - IPAMConfig: IP 주소 관리 설정 (예: IPv4Address, IPv6Address 등) |
3.2 create_networking_config(endpoints_config):
- 개별 네트워크 연결에 대한 설정을 생성한다. 컨테이너가 네트워크에 연결될 때 사용되는 엔드포인트(endpoint) 구성 객체를 생성하는 헬퍼 함수이다.
- 이 함수는 각 네트워크에 대해 컨테이너가 사용할 고정 IP 주소, 네트워크 내에서의 별칭(aliases), 다른 컨테이너와의 링크 정보, 링크 로컬 IP(link-local IP) 및 네트워크 드라이버에 특화된 옵션(driver_opt) 등을 지정할 수 있게 해준다.
- 생성된 엔드포인트 구성 객체는 이후 컨테이너의 네트워킹 설정(예, NetworkingConfig의 엔트리)으로 전달되어 컨테이너가 해당 네트워크에 원하는 방식으로 연결되도록 한다.
- 주요 기능 및 사용 용도
- 엔드포인트 구성 생성:
- 네트워크에 연결할 때, 컨테이너별로 고정 IP, 별칭, 링크 정보 등 세부 설정을 하나의 구성 객체로 결합하여 Docker API에 전달할 수 있도록 한다.
- 네트워크 연결 세부 제어:
- 여러 네트워크에 연결할 때, 각 네트워크별로 개별 엔드포인트 설정을 지정할 수 있으므로, 복잡한 네트워크 토폴로지 구성이나 특정 요구사항(예: 특정 IP 할당, 드라이버 옵션 전달 등)을 만족시킬 수 있다.
from docker.types import EndpointConfig
# 엔드포인트 구성 객체 생성 예시
endpoint_config = create_endpoint_config(
aliases=["webserver"],
links=["db:database"],
ipv4_address="172.20.0.5",
ipv6_address=None,
link_local_ips=["169.254.1.5"],
driver_opt={"custom_option": "value"}
)
# 생성된 endpoint_config 객체는 NetworkingConfig 구성의 일부로 사용될 수 있습니다.
# 예를 들어, 여러 네트워크에 연결할 경우 각 네트워크 이름을 키로 하여 엔드포인트 설정을 지정합니다:
endpoints_config = {
"bridge": endpoint_config,
"custom_net": create_endpoint_config(
aliases=["web_custom"],
ipv4_address="192.168.1.100",
driver_opt={"opt1": "value1"}
)
}
networking_config = client.create_networking_config(endpoints_config)
container = client.create_container(
image="your-image",
name="my_container",
networking_config=networking_config
)
- 매개변수 정보
매개변수 | 자료형 | 설명 |
aliases | list of str | 해당 네트워크 내에서 컨테이너가 사용할 추가 별칭(호스트명) 목록입니다. |
links | list | 다른 컨테이너와의 링크 정보를 지정합니다. 일반적으로 "컨테이너명:별칭" 형식의 문자열 리스트로 제공됩니다. |
ipv4_address | str | 컨테이너에 할당할 고정 IPv4 주소입니다. |
ipv6_address | str | 컨테이너에 할당할 고정 IPv6 주소입니다. (없으면 None으로 설정) |
link_local_ips | list of str | 컨테이너에 할당할 링크 로컬 IP 주소들의 리스트입니다. |
driver_opt | dict | 네트워크 드라이버에 전달할 추가 옵션들을 담은 딕셔너리입니다. |
4. volume: 볼륨 관리
- list()
- 설명:
- 현재 존재하는 모든 볼륨 목록을 조회한다.
- list()의 매개변수
매개변수 | 타입 | 기본값 | 설명 |
filters | dict | None | 특정 조건으로 볼륨을 필터링 (예: { "dangling": ["true"] }) |
- create()
- 설명:
- 새로운 볼륨을 생성한다.
- create()의 매개변수
매개변수 | 타입 | 기본값 | 설명 |
name | str | None | 생성할 볼륨의 이름 |
driver | str | "local" | 사용할 드라이버 (예: "local", "nfs") |
driver_opts | dict | {} | 드라이버에 전달할 추가 옵션 |
labels | dict | {} | 볼륨에 추가할 레이블 |
- get()
- 설명:
- 특정 볼륨의 정보를 가져온다.
- get()의 매개변수
매개변수 | 타입 | 기본값 | 설명 |
name | str | 없음 | 조회할 볼륨의 이름 |
- prune()
- 설명:
- 사용되지 않는 볼륨을 정리(삭제)한다.
- prune()의 매개변수
매개변수 | 타입 | 기본값 | 설명 |
filters | dict | None | 특정 조건으로 볼륨 정리 (예: { "until": "24h" }) |
- remove()
- 설명:
- 특정 볼륨을 삭제한다.
- remove()의 매개변수
매개변수 | 타입 | 기본값 | 설명 |
name | str | 없음 | 삭제할 볼륨의 이름 |
force | bool | FALSE | 볼륨이 사용 중일 경우 강제 삭제 여부 |
volume = client.volumes.create(
name="my-volume",
driver="local",
labels={"type": "database"}
)
# 볼륨 마운트로 컨테이너 실행
client.containers.run(
"postgres:13",
volumes={'my-volume': {'bind': '/var/lib/postgresql/data', 'mode': 'rw'}},
detach=True
)
3) 컨테이너 상태 모니터링
1. 기능/메소드 정리
1.1 컨테이너 목록 조회
- client.containers.list(all=True)
- 실행 중이거나 종료된 모든 컨테이너 목록을 가져온다.
1.2 특정 컨테이너 객체 가져오기
- client.containers.get(container_id_or_name)
- 특정 컨테이너 객체를 얻어 상세 정보를 조회할 수 있다.
1.3 컨테이너 속성 확인
- container.status
- 현재 상태(예: "running", "exited", "paused" 등)를 문자열로 반환한다.
- container.attrs
- 컨테이너에 대한 전체 정보를 딕셔너리 형태로 제공한다.
- container.logs()
- 컨테이너의 로그를 가져온다.
1.4 컨테이너 정보 갱신
- ontainer.reload()
- 컨테이너의 내부 상태 정보를 최신 상태로 새로 고친다.
1.5 이벤트 모니터링
- client.events(decode=True)
- Docker 데몬에서 발생하는 이벤트(컨테이너 생성, 시작, 종료 등)를 실시간으로 구독할 수 있다.
2. 모니터링 방식
2.1 이벤트 기반 모니터링
- Docker 데몬에서 발생하는 이벤트를 실시간으로 구독하여, 컨테이너의 상태 변화(예: 생성, 시작, 종료, 재시작 등)를 감지할 수 있다.
- 주요 메소드는 client.events(decode=True)이다.
2.2 주기적 폴링(Polling) 방식
- 정해진 간격으로 모든 컨테이너의 상태를 조회(예: client.containers.list(all=True))하고, 각 컨테이너의 상태(container.status)를 비교하여 변경 사항이 있으면 이를 기록하는 방식이다.
3. 실무 레벨 샘플 코드
3.1 이벤트 기반 모니터링
- 이 코드는 Docker 데몬의 이벤트 스트림을 구독하여, 컨테이너 관련 이벤트가 발생할 때마다 해당 컨테이너의 이름과 상태를 로깅한다.
- docker.from_env()를 사용하여 환경변수 기반의 클라이언트를 생성한다.
- client.events(decode=True)를 통해 이벤트 스트림을 받아오고, 각 이벤트에서 "Type"이 "container"인 경우 상태(status)와 컨테이너 ID를 가져온다.
- 컨테이너 이름은 추가 조회(get) 후 출력한다.
import docker
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
def monitor_container_events():
client = docker.from_env()
logging.info("Docker 컨테이너 이벤트 모니터링을 시작합니다.")
try:
for event in client.events(decode=True):
# 이벤트 타입이 컨테이너인 경우만 처리
if event.get("Type") == "container":
status = event.get("status", "unknown")
container_id = event.get("id", "")[:12]
try:
container = client.containers.get(container_id)
name = container.name
except Exception:
name = "N/A"
logging.info("컨테이너 [%s] (%s): 이벤트 -> %s", name, container_id, status)
except Exception as e:
logging.error("이벤트 모니터링 중 오류 발생: %s", e)
if __name__ == "__main__":
monitor_container_events()
3.2 주기적 폴링 방식
- 이 코드는 일정 주기로 모든 컨테이너의 상태를 조회하여, 이전 상태와 비교한 후 변화가 있으면 이를 로깅한다.
- 주어진 간격(기본 5초)마다 모든 컨테이너 목록을 조회한다.
- 각 컨테이너에 대해 container.reload()를 호출하여 최신 상태를 반영한 후 container.status를 확인한다.
- 이전에 저장한 상태와 비교하여 변경이 있으면 로깅한다.
import docker
import logging
import time
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
def poll_containers_status(poll_interval=5):
client = docker.from_env()
known_status = {}
while True:
try:
containers = client.containers.list(all=True)
for container in containers:
# 최신 상태를 위해 컨테이너 정보를 갱신
container.reload()
current_status = container.status
if container.id not in known_status:
known_status[container.id] = current_status
logging.info("컨테이너 [%s] (%s)의 초기 상태: %s", container.name, container.id[:12], current_status)
elif known_status[container.id] != current_status:
logging.info("컨테이너 [%s] (%s) 상태 변경: %s -> %s",
container.name, container.id[:12], known_status[container.id], current_status)
known_status[container.id] = current_status
time.sleep(poll_interval)
except Exception as e:
logging.error("폴링 중 오류 발생: %s", e)
time.sleep(poll_interval)
if __name__ == "__main__":
poll_containers_status()
4) docker.APIClient를 이용한 저수준 API 사용
- Docker 엔진의 REST API와 1:1로 매핑되는 저수준 인터페이스를 제공한다.
- 고수준 인터페이스(예: docker.from_env()를 통해 얻는 client)는 여러 작업을 한 번에 쉽게 처리할 수 있도록 래핑하지만, 보다 세밀한 제어가 필요할 때는 APIClient를 직접 사용하는 것이 유용하다.
- 예를 들어, 이미지 빌드 과정에서 캐시 제어, 중간 컨테이너 제거 옵션, 빌드 아규먼트 전달 등 다양한 옵션을 세밀하게 조정할 수 있다.
1. 기본 설정 및 연결
- Docker 데몬과 통신하려면 APIClient 인스턴스를 생성할 때 데몬의 소켓(일반적으로 Unix 소켓 또는 TCP 주소)을 지정해야 한다.
- APIClient 초기화
- base_url에는 Docker 데몬의 주소를 지정한다.
- version() 메서드를 통해 데몬의 API 버전, OS, 아키텍처 등 다양한 정보를 확인할 수 있다.
import docker
# Unix 소켓을 통한 연결 (리눅스나 macOS에서 사용)
client = docker.APIClient(base_url='unix://var/run/docker.sock')
# 또는 TCP 연결 (예: 도커 데몬이 TCP로 노출되어 있을 경우)
# client = docker.APIClient(base_url='tcp://127.0.0.1:2375')
# 데몬 버전 확인 (버전 정보는 딕셔너리 형태로 반환됨)
version_info = client.version()
print("Docker 서버 버전:", version_info.get('Version'))
2. 주요 기능 및 사용 예제
2.1 이미지 빌드 (Build)
- 저수준 API를 사용하면 Dockerfile을 기반으로 이미지를 빌드할 수 있다.
- 빌드 결과는 제너레이터(generator) 형태로 반환되며, 각 단계의 출력을 읽어야 한다.
- 예제: 간단한 Dockerfile로 이미지 빌드
- custom_context 옵션을 사용하면 Dockerfile 외의 컨텍스트(필요한 파일 등)를 함께 전달할 수 있다.
- rm 옵션은 빌드 완료 후 중간 컨테이너를 자동 삭제한다.
- decode=True를 사용하면 반환된 스트림이 JSON 디코딩되어 보다 쉽게 처리할 수 있다.
import io
from docker import APIClient
# Dockerfile 내용을 문자열로 작성
dockerfile_str = '''
# 베이스 이미지를 busybox로 설정
FROM busybox:latest
# /data 디렉토리를 볼륨으로 선언
VOLUME /data
# 기본 커맨드는 쉘 실행
CMD ["/bin/sh"]
'''
# 문자열을 바이트 스트림으로 변환 (BytesIO 객체 사용)
dockerfile_stream = io.BytesIO(dockerfile_str.encode('utf-8'))
# APIClient 생성 (Unix 소켓 사용)
client = APIClient(base_url='unix://var/run/docker.sock')
# 이미지 빌드: fileobj 인자에 Dockerfile의 파일 스트림을 전달, custom_context=True로 지정
build_output = client.build(
fileobj=dockerfile_stream,
custom_context=True,
tag='my_busybox:latest',
rm=True, # 빌드 중간 컨테이너 제거 옵션
decode=True # 출력 스트림을 JSON 디코딩하여 dict 형태로 받음
)
# 빌드 과정 출력 (각 단계의 스트림 출력)
print("이미지 빌드 출력:")
for line in build_output:
# 각 라인은 dict 형태이므로 'stream' 키의 값을 출력 (빌드 로그 메시지)
print(line.get('stream', '').strip())
2.2 컨테이너 생성 및 실행
- 이미지로부터 컨테이너를 생성하고 실행하는 작업은 여러 API 호출로 구성된다.
- 주요 메서드는 create_container(), start(), wait(), logs() 등이 있다.
- 예제: 컨테이너 생성, 실행, 로그 확인 및 종료
- create_container()에서는 Docker run 커맨드와 유사하게 이미지를 지정하고 실행할 커맨드를 설정한다.
- start()로 컨테이너를 시작하고, wait()로 프로세스 종료를 대기한다.
- logs()는 컨테이너에서 출력된 로그를 가져온다. (바이트 문자열로 반환되므로 decode 필요)
# 1. 컨테이너 생성: create_container() 메서드 사용
container_config = {
'Image': 'my_busybox:latest', # 빌드한 이미지 태그 사용
'Cmd': ['/bin/sh', '-c', 'echo "Hello from container!"'],
'Tty': False
}
container = client.create_container(**container_config)
container_id = container.get('Id')
print("생성된 컨테이너 ID:", container_id)
# 2. 컨테이너 시작: start() 메서드 사용
client.start(container=container_id)
print("컨테이너 시작됨.")
# 3. 컨테이너가 종료될 때까지 대기: wait() 메서드 사용
exit_status = client.wait(container=container_id)
print("컨테이너 종료 상태:", exit_status.get('StatusCode'))
# 4. 컨테이너 로그 확인: logs() 메서드 사용 (전체 로그 문자열 반환)
logs_output = client.logs(container=container_id, stdout=True, stderr=True)
print("컨테이너 로그:\n", logs_output.decode('utf-8'))
# 5. 컨테이너 삭제: remove_container() 메서드 사용 (컨테이너가 종료된 후)
client.remove_container(container=container_id)
print("컨테이너 삭제됨.")
2.3 컨테이너 내 명령 실행 (Exec)
- 실행 중인 컨테이너 내부에서 추가 명령을 실행하고자 할 때는 exec 인스턴스를 생성한 후 시작한다.
- 예제: 컨테이너 내부에서 명령 실행
- exec_create()로 실행할 명령과 옵션을 설정한 후, 생성된 exec 인스턴스의 ID를 이용해 명령을 실행한다.
- exec 명령은 컨테이너 내부의 쉘 환경에서 실행된다.
# 1. 컨테이너 내부에서 실행할 명령 설정 (예: 'echo "Exec 명령 실행"' 실행)
exec_command = ['echo', 'Exec 명령 실행']
# 2. exec 인스턴스 생성: exec_create() 메서드 사용
exec_instance = client.exec_create(
container=container_id,
cmd=exec_command,
stdout=True,
stderr=True
)
exec_id = exec_instance.get('Id')
print("생성된 exec 인스턴스 ID:", exec_id)
# 3. exec 명령 시작: exec_start() 메서드 사용
# stream=False이면 전체 결과를 한 번에 반환, stream=True이면 제너레이터 반환
exec_output = client.exec_start(exec_id, stream=False)
print("Exec 결과:", exec_output.decode('utf-8'))
2.4 컨테이너 커밋 (Commit)
- 실행된 컨테이너의 상태를 이미지로 저장할 수 있습니다. 이는 docker commit과 유사하다.
- 예제: 컨테이너를 커밋하여 새 이미지 생성
- commit() 메서드는 컨테이너의 현재 상태를 스냅샷처럼 이미지로 저정한다.
- 옵션으로 커밋 메시지, 작성자 정보 등을 포함할 수 있다.
commit_config = {
'repository': 'my_committed_image',
'tag': 'latest',
'message': '컨테이너 상태 커밋',
'author': '작성자 이름'
}
commit_response = client.commit(container=container_id, **commit_config)
new_image_id = commit_response.get('Id')
print("새로 커밋된 이미지 ID:", new_image_id)
3. 추가 기능
3.1 로그 스트리밍
실시간으로 로그를 모니터링하려면 logs() 메서드에 stream=True 옵션을 주어 제너레이터로 사용한다.
# 로그 스트리밍: 컨테이너 로그를 실시간으로 읽어오기
log_stream = client.logs(container=container_id, stdout=True, stderr=True, stream=True)
print("실시간 로그 출력:")
for log_line in log_stream:
print(log_line.decode('utf-8').strip())
import docker
def exec_in_container():
client = docker.from_env()
container = client.containers.run("ubuntu", "sleep 60", detach=True)
# 컨테이너 내부에서 명령어 실행
exit_code, output = container.exec_run("echo '고급 실행 예제'")
print("exec_run 출력:", output.decode('utf-8'))
# 스트리밍 방식으로 로그 출력 (컨테이너가 출력하는 로그를 실시간 모니터링)
for log_line in container.logs(stream=True):
print(log_line.decode('utf-8').strip())
container.stop()
container.remove()
if __name__ == '__main__':
exec_in_container()
3.2 기타 유용한 메서드
- get_archive() / put_archive()
- 컨테이너 내부의 파일이나 폴더를 tar 아카이브 형태로 가져오거나 업로드할 수 있다.
- diff()
- 컨테이너의 파일 시스템 변경 사항을 확인할 수 있다.
- resize()
- TTY 세션의 크기를 변경할 수 있다.
- stats()
- 컨테이너의 리소스 사용량(메모리, CPU 등)을 스트리밍 방식으로 모니터링할 수 있다.
5) Swarm 명령어 (Swarm Commands)
1. service: Swarm 서비스 관리
service = client.services.create(
image="nginx:alpine",
name="web-service",
replicas=3,
networks=["my-overlay-network"],
mounts=[
docker.types.Mount(
target="/usr/share/nginx/html",
source="web-content",
type="volume"
)
],
endpoint_spec=docker.types.EndpointSpec(ports={80: 8080})
)
3. 실무 프로젝트 시나리오
1) 분산 마이크로서비스 아키텍처
- 구성 요소:
- Flask API 서버 (포트 5000)
- Redis 캐시 (볼륨 마운트)
- Nginx 로드 밸런서 (사용자 정의 네트워크)
# 1. 네트워크 생성
network = client.networks.create("msa-network", driver="bridge")
# 2. Redis 컨테이너 실행 (볼륨 포함)
redis_vol = client.volumes.create("redis-data")
redis = client.containers.run(
"redis:6",
volumes={redis_vol.name: {'bind': '/data', 'mode': 'rw'}},
network="msa-network",
detach=True
)
# 3. Flask API 실행
flask = client.containers.run(
"my-flask-image:latest",
environment={"REDIS_HOST": "redis"},
ports={'5000/tcp': 5000},
network="msa-network",
detach=True
)
# 4. Nginx 실행 (커스텀 설정 파일 마운트)
nginx = client.containers.run(
"nginx:latest",
volumes={'/path/nginx.conf': {'bind': '/etc/nginx/nginx.conf', 'mode': 'ro'}},
ports={'80/tcp': 8080},
network="msa-network",
detach=True
)
- reference :
'개발언어 Back-End > Python' 카테고리의 다른 글
Python Logging 사용 방법 정리 (0) | 2025.02.13 |
---|---|
컴프리헨션 / 제너레이터 정리 / 지연평가 (0) | 2025.02.12 |
파이썬에서 CPU와 메모리 사용량을 추적하는 방법 (0) | 2024.05.14 |
함수안에 데이터클래스 정의의 용도와 사용 예시 (0) | 2024.03.17 |
데이터 클래스(dataclasses ) 의 사용목적, 단점, 사용 예시 (1) | 2024.02.01 |
댓글