설치
# 테스트용 (공식 편의 스크립트)
curl -fsSL https://get.docker.com | sh
# 설치 확인
docker version
편의 스크립트는 공식 문서에서도 운영 환경용으로는 권장하지 않는다.
운영 서버라면 공식 문서의 배포판별 apt/dnf 저장소 방식으로 설치하는 게 맞다.
참고로 apt install docker.io는 Docker 공식 패키지가 아니라 배포판이 관리하는 패키지라서 버전이 꽤 뒤처져 있을 수 있다.
매일 치는 것들
# 테스트용으로 띄웠다가 끝나면 알아서 삭제
docker run --rm -it ubuntu:22.04 bash
# 백그라운드 실행 + 포트 연결
docker run -d -p 8080:80 --name web nginx
# 실행 중인 컨테이너 들어가기
docker exec -it web sh
# 로그 (마지막 100줄부터 계속 따라가기)
docker logs -f --tail 100 web
# 파일 넣고 빼기
docker cp ./foo.txt web:/tmp/foo.txt
docker cp web:/tmp/foo.txt ./foo.txt
--rm은 테스트할 때 거의 필수다.
안 붙이면 docker ps -a에 죽은 컨테이너가 태산같이 쌓인다.
리소스 확인
# 컨테이너별 CPU/메모리 사용량
docker stats --no-stream
# 컨테이너 안에서 돌고 있는 프로세스
docker top web
# 호스트 기준 PID 확인
docker inspect --format '{{.State.Pid}}' web
# 디스크를 누가 먹고 있는지
docker system df
docker system df는 정리하기 전에 꼭 먼저 쳐보자.
이미지인지, 빌드 캐시인지, 볼륨인지 알고 지워야 덜 무섭다.
빌드와 푸시
# 빌드 (마지막 점은 빌드 컨텍스트! 빼먹으면 에러)
docker build -t myapp:1.0.0 .
# 멀티 아키텍처 빌드 + 바로 푸시
docker buildx build --platform linux/amd64,linux/arm64 \
-t registry.example.com/myapp:1.0.0 --push .
# 태그 붙이고 푸시
docker tag myapp:1.0.0 registry.example.com/myapp:1.0.0
docker push registry.example.com/myapp:1.0.0
ARM 맥북에서 빌드한 이미지를 amd64 서버에 올렸다가 exec format error를 한 번이라도 본 사람이라면 --platform의 소중함을 알 것이다.
레지스트리에 태그 불변성(Tag Immutability)이 걸려 있으면 같은 태그로 다시 푸시하는 게 거부된다.
이럴 땐 태그를 덮어쓰려 하지 말고 커밋 SHA 같은 고유값으로 태그를 붙이는 습관을 들이는 게 낫다.
정리하기
# 멈춘 컨테이너, 안 쓰는 네트워크, dangling 이미지, 빌드 캐시 정리
docker system prune
# 컨테이너가 안 쓰는 이미지까지 전부
docker system prune -a
# 종료된(exited) 컨테이너만
docker rm $(docker ps -aq --filter status=exited)
# 안 쓰는 볼륨
docker volume prune
- docker volume prune은 컨테이너에 연결되지 않은 볼륨을 이름 있는 것까지 전부 지운다.
컨테이너를 잠깐 내려둔 사이에 치면 DB 데이터 볼륨이 날아갈 수 있으니 한 번 더 확인하고 치자.
자주 만나는 에러
1. permission denied ... docker.sock
sudo usermod -aG docker $USER
newgrp docker
자세한 건 예전에 쓴 ECR 업로드 시 Docker 권한 문제 글 참고.
참고로 docker 그룹은 사실상 root 권한이라 공용 서버에서는 신중하게 줘야 한다.
2. 컨테이너가 Exit Code 137로 죽음
docker inspect --format '{{.State.OOMKilled}}' web
true면 메모리 한도를 넘어서 커널이 죽인 거다.
3. Storage Driver 확인
docker info --format '{{.Driver}}'