docker images
docker image ls
서론
팀 프로젝트를 진행하거나, 포트폴리오를 만들 때 빼놓을 수 없는 것이 배포와 운영일 것이다. 또한 최근 클라우드가 각광 받으며 관련된 도커나, 쿠버네티스 기술에 관심을 갖는 사람들도 늘었다. 많은 사람들이 사용하는 만큼 그 이유가 있을 것이다. 공부를 시작하기에 앞서 이 기술들이 왜 쓰이는지부터 알아보자
중요한 것은 추상화, 격리
컨테이너는 실행에 필요한 모든 파일을 포함한 전체 실행(runtime) 환경에서 애플리케이션을 패키징하고 격리할 수 있는 기술입니다. 이를 통해 전체 기능을 유지하면서 컨테이너화된 애플리케이션을 환경(개발, 테스트, 프로덕션 환경 등) 간에 쉽게 이동할 수 있습니다. 컨테이너는 IT 보안의 중요한 부분이기도 합니다. 컨테이너 파이프라인에 보안을 구축하고 인프라를 보호하여 컨테이너의 안정성, 확장성, 신뢰성을 보장할 수 있습니다. 또한 일관된 행동과 기능으로 퍼블릭, 프라이빗, 하이브리드 클라우드 환경과 데이터센터(또는 온프레미스) 간에 컨테이너화된 애플리케이션을 손쉽게 이동할 수 있습니다.
컨테이너 보안이란 애플리케이션, 기반 인프라, 소프트웨어 공급 네트워크, 런타임 등 컨테이너의 모든 요소가 안전하게 실행되도록 보안 도구 및 정책을 구현하는 과정을 말한다. 레드햇 홈페이지에서도 언급하듯, 컨테이너는 애플리케이션을 패키징하고 격리한다. 이는 개발자가 초기 설정과 배포에 소요되는 시간을 줄이고, 개발에 더 많은 시간을 투자할 수 있도록 해준다. 잦은 변화에 빠르게 대응할 수 있기에 컨테이너 기술이 각광받는 이유이다.
이를 통해 우리는 컨테이너 기술의 중요성과 그 사용 이유를 명확히 이해할 수 있다. 특히 서비스 개수 만큼 서버의 개수가 늘어나 수백 수천개의 상황이라면 배포와 운영에서의 효율성, 보안 강화, 그리고 다양한 환경 간의 유연한 이동성을 제공하는 이 기술들은 현대 개발 환경에서 필수라는 것을 더욱 이해할 수 있을 것이다.
VM vs Container
기존 virtual machine은 Hypervisor위 머신 별로 별도의 OS를 포함하고 있어서 무겁고, 느리다. 반면, Container는 격리된 상태에서 Linux의 커널을 공유하여 사용하기에 별도의 OS가 없고, 빠르게 배포할 수 있고 가볍다.
Docker
- 도커에서 핵심이 되는 것은 Docker daemon이다. 사용자가 docker 명령어를 사용하여 api를 사용하면 Docker daemon이 이를 처리한다.
- Dockerfile에 작성한 명령어들은 이미지로 빌드가 되어 Registry에 저장된다.
- 이미지는 컨테이너를 만드는 Template이다.
Docker CLI
docker search [OPTIONS] <keyword>
Registry에서 이미지를 검색한다.
docker pull [OPTIONS] REPOSITORY[:TAG|@DIGEST]
Registry에서 이미지를 다운로드 받는다. DIGEST 값을 사용하여 정확한 버전의 이미지를 검색할 수 있으며, tag를 사용하여서도 검색할 수 있다. REPOSITORY만 입력한 경우 자동으로 latest를 다운로드 받는다.
docker images [OPTIONS] [REPOSITORY[:TAG]]
이미지 목록을 조회 할 수 있다. REPOSITORY만 명시한 경우 해당 이름만 가진 이미지만 검색한다.
docker rmi [OPTIONS] IMAGE [IMAGE...]
한개 이상의 명시된 이미지를 삭제한다.
docker image prune [OPTIONS]
모든 dangling 이미지를 삭제한다. dangling 이미지란, Repository가 none으로 표기되는 이미지를 의미한다. 일반적으로 dangling 이미지는 동일한 이름(Name & tag)를 가진 다른 이미지를 생성하는 경우, Multi-Stage 빌드 중 중간이미지로 생성된다.
docker inspect [OPTIONS] NAME|ID [NAME|ID...]
이미지의 자세한 정보를 출력한다.
root@8ab92b491e04:/code (eks:default)# docker inspect tlgusdl03/fortunek8s
[
{
"Id": "sha256:2de760906e5f889b848ae18ae310df0451f48dd6e17bb78937eda796b1789324",
"RepoTags": [
"tlgusdl03/fortunek8s:latest",
"tlgusld03/fortunek8s:latest"
],
"RepoDigests": [
"tlgusdl03/fortunek8s@sha256:9655a5837bc147ac0b554f70c6ad4a2fcde3dc0638e65ea1a427b85b4d696762"
],
"Parent": "",
"Comment": "buildkit.dockerfile.v0",
"Created": "2024-07-18T01:26:19.591960778Z",
"ContainerConfig": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": null,
"Cmd": null,
"Image": "",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"DockerVersion": "",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": null,
"Image": "",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": [
"/bin/sh",
"-c",
"/bin/fortuneloop.sh"
],
"OnBuild": null,
"Labels": {
"org.opencontainers.image.ref.name": "ubuntu",
"org.opencontainers.image.version": "24.04"
}
},
"Architecture": "amd64",
"Os": "linux",
"Size": 119436304,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/x0wtovjx3g70a5prm0t081gc2/diff:/var/lib/docker/overlay2/vbz7beipmwg6ze4nevy98mxsn/diff:/var/lib/docker/overlay2/4a0eee8e4a9200ef4888fd1240d3fdaaeca58bc61298362105ab0e6cd730fab8/diff",
"MergedDir": "/var/lib/docker/overlay2/zgtelj2sdekvhfi100194yz2v/merged",
"UpperDir": "/var/lib/docker/overlay2/zgtelj2sdekvhfi100194yz2v/diff",
"WorkDir": "/var/lib/docker/overlay2/zgtelj2sdekvhfi100194yz2v/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:a30a5965a4f7d9d5ff76a46eb8939f58e95be844de1ac4a4b452d5d31158fdea",
"sha256:fd0da0897a09e46a4f3aef40bf27dd867f4f71f6ccdd5c0b7a2513b2ea982924",
"sha256:02d6da2fb15a37bc9563bf677741e2c0d50bc02c42823c0764a7a8f7b77bb720",
"sha256:1a6b4964972e54f1527d8d193697d64bb3f28b12fcd22c0f1e20cb5062e1c624"
]
},
"Metadata": {
"LastTagTime": "2024-07-18T01:45:14.930905494Z"
},
"Container": ""
}
]
이미지에 있어서 가장 중요한 레이어를 확인할 수 있다.
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
이미지를 통해 컨테이너를 실행한다.
Option | Short | Description |
--name | 컨테이너의 이름을 지정함 | |
--detach | -d | 컨테이너를 백그라운드에서 실행함 |
--env | -e | 환경변수를 설정함 |
--env-file | 환경 변수를 저장한 파일을 설정함, 여러개의 환경변수를 설정할 때 사용함 | |
--expose | 포트 또는 포트 범위를 노출함, 같은 네트워크의 컨테이너의 통신이 가능하게 함 | |
--publish | -p | 컨테이너의 포트를 공개함, 호스트 또는 외부와의 통신이 가능하게 함 |
--rm | 컨테이너가 종료되면 자동으로 삭제함 | |
--interactive | -i | STDIN을 활성화 함 |
--tty | -t | pseudo-TTY를 활성화 함 |
--volume | -v | 볼륨을 설정함 |
docker ps [OPTIONS]
동작중인 컨테이너의 목록을 볼 수 있다. -a 옵션과 함께하면, 종료된 컨테이너의 목록도 볼 수 있다.
docker logs [OPTIONS] <NAME_OR_ID>
컨테이너의 로그를 확인할 수 있다.
docker exec -it [OPTIONS] <ID_OR_NAME> /bin/bash|sh|...
현재 실행중인 컨테이너에서 새로운 명령어를 실행한다. 메인 프로세스가 실행되는 동안에만 명령어를 실행할 수 있고, exec로 실행된 명령은 컨테이너 재실행시 실행되지 않는다. 또한 일부 이미지로 생성된 컨테이너는 bash, sh과 같은 shell이 없을 수 있다.
# 종료
docker stop <NAME_OR_ID>
# 시작
docker start <NAME_OR_ID>
# 중지
docker pause <NAME_OR_ID>
# 재실행
docker unpause <NAME_OR_ID>
start와 stop의 경우 재실행 할 시 Dockerfile을 통해 실행되지 않은 프로세스는 재실행되지 않는다. pause와 unpause를 통해 중지된 경우에는 모든 프로세스가 재실행된다.
docker rm [OPTIONS] CONTAINER [CONTAINER...]
컨테이너를 삭제한다. --force, -f 옵션을 통해 실행중인 컨테이너를 강제로 삭제할 수 있고, --volumes, -v 옵션을 통해 컨테이너의 annonymous volumes도 함께 삭제할 수 있다.
docker build [OPTIONS] PATH | URL | - [-f <PATH_TO_FILE>]
docker buildx build [OPTIONS] PATH | URL | - [-f <PATH_TO_FILE>]
Dockerfile을 이미지로 빌드한다. -f를 통해 dockerfile의 위치와 이름을 지정할 수 있고 지정하지 않았다면 같은 디렉토리의 Dockerfile을 찾는 것이 디폴트이다. -t 옵션을 통해 이미지의 이름과 Tag를 설정할 수 있다.
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
이미지의 이름과 태그를 변경할 수 있다.
docker push [OPTIONS] NAME[:TAG]
이미지를 Docker hub 또는 별도의 registry에 업로드 할 수 있다. 이를 위해 사전에 docker login을 통해 registry에 인증해야 한다.