도커 기초
Introduction
Docker가 설치되어 있는지 확인
docker --version
생성된 모든 컨테이너 목록 확인
docker container ls -a
Docker 실행 옵션 확인 - Docker 구조
sudo systemctl status docker.service --no-pager
containerd 상태 확인 - https://www.docker.com/blog/docker-engine-1-11-runc/
sudo systemctl status containerd.service --no-pager
Docker CLI로 컨테이너 생성
docker container run --name nginx --detach --publish 8080:80 nginx
현재 실행중인 컨테이너 목록 확인
docker container ls
로컬호스트에 연동된 포트로 HTTP 요청
curl localhost:8080
runc가 생성한 컨테이너 확인
sudo runc --root /run/docker/runtime-runc/moby list
컨테이너를 통해서 실행된 프로세스 확인
sudo runc --root /run/docker/runtime-runc/moby ps \ $(sudo runc --root /run/docker/runtime-runc/moby list -q)
위에서 생성한 컨테이너 삭제 시도
docker container rm nginx
실행중인 컨테이너 정지
docker container stop nginx
컨테이너 삭제
docker container rm nginx
생성된 모든 컨테이너 목록 확인
docker container ls -a
지난 30분간 Docker에서 발생한 이벤트 확인
docker system events --since '30m' --until $(date +%s)
컨테이너 이미지 구조
Apache 컨테이너 이미지 다운로드
docker image pull apache
Docker Hub에서 Apache 컨테이너 이미지 검색
Apache 컨테이너 이미지 다운로드
docker image pull httpd
Docker Hub에서 latest 태그를 가진 Apache 컨테이너 이미지의 상세 내용 확인
Docker Hub에서 alpine 태그를 가진 Apache 컨테이너 이미지의 상세 내용 확인
Alpine 리눅스를 사용하는 Apache 컨테이너 이미지 다운로드
docker image pull httpd:alpine
로컬호스트에 저장된 컨테이너 이미지 확인
docker image ls
alpine 태그를 가진 Apache 컨테이너 이미지의 상세 내용 확인
docker image inspect httpd:alpine
alpine 태그를 가진 Apache 컨테이너 이미지 삭제
docker image rm httpd:alpine
bookworm 태그를 가진 NGINX 컨테이너 이미지 다운로드
docker image pull nginx:bookworm
로컬호스트에 저장된 컨테이너 이미지 확인
docker image ls
bookworm 태그를 가진 NGINX 컨테이너 이미지 삭제
docker image rm nginx:bookworm
새로운 컨테이너 이미지 빌드
cat <<EOF | docker image build -t flask - FROM python RUN apt update && apt install -y curl RUN useradd developer CMD ['python'] RUN pip install Flask EOF
로컬호스트에 저장된 컨테이너 이미지 확인
docker image ls
컨테이너 이미지 빌드에 사용한 베이스 이미지 다운로드
docker image pull python
python과 flask 이미지의 Layer 비교
diff <(docker image inspect python:latest --format '{{range .RootFS.Layers}}{{println .}}{{end}}') <(docker image inspect flask:latest --format '{{range .RootFS.Layers}}{{println .}}{{end}}') -y
flask 이미지의 상세 내용 확인
docker image inspect flask:latest
마지막에 수행되는 명령만 변경해서 새로운 이미지 빌드
cat <<EOF | docker image build -t boto3 - FROM python RUN apt update && apt install -y curl RUN useradd developer CMD ['python'] RUN pip install boto3 EOF
flask와 boto3 이미지의 Layer 비교
diff <(docker image inspect flask:latest --format '{{range .RootFS.Layers}}{{println .}}{{end}}') <(docker image inspect boto3:latest --format '{{range .RootFS.Layers}}{{println .}}{{end}}') -y
이미지 삭제
docker image prune -a --force
이미지 생성 및 공유
데모 애플리케이션 소스코드 다운로드
cd ~/environment && git clone https://github.com/youngwjung/express-hello-world.git && cd express-hello-world
애플리케이션 구동에 필요한 라이브러리 설치
npm install
애플리케이션 구동
node app.js
새로운 터미널을 열고 웹 애플리케이션이 구동하는지 확인
curl -w "\n" localhost:8080
기존 터미널로 돌아와서
Ctrl+C
를 입력해서 애플리케이션 정지Dockerfile 리뷰
컨테이너 이미지 빌드
docker image build -t express-hello-world .
컨테이너 실행
docker container run --name hello-world -d -p 8080:3000 express-hello-world
컨테이너가 정상적으로 실행 되었는지 확인
curl -w "\n" localhost:8080
컨테이너 삭제
docker container rm hello-world --force
ECR 리포지토리 생성
aws ecr create-repository \ --repository-name express-hello-world \ --no-cli-pager
위에서 생성한 ECR 리포지토리의 URI를 확인하고 환경변수로 지정
{ export ECR_REPO=$(aws ecr describe-repositories --repository-name express-hello-world \ --query 'repositories[0].repositoryUri' \ --output text) echo $ECR_REPO }
위에서 생성한 컨테이너 이미지에 새로운 태그 부여
docker image tag express-hello-world $ECR_REPO
컨테이너 이미지 목록 확인
docker image ls
컨테이너 이미지를 ECR 리포지토리로 업로드
docker image push $ECR_REPO
ECR 레지스트리로 로그인
{ export ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) export AWS_REGION=$(aws ec2 describe-availability-zones --output text --query 'AvailabilityZones[0].[RegionName]') aws ecr get-login-password | docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com }
컨테이너 이미지를 ECR 리포지토리로 업로드
docker image push $ECR_REPO
이미지가 정상적으로 업로드 되었는지 확인
aws ecr list-images --repository-name express-hello-world
로컬호스트에 생성된 모든 컨테이너 삭제
docker container rm $(docker container ls -aq) --force
로컬호스트에 저장된 모드 컨테이너 이미지 삭제
{ docker image prune --all --force docker system prune --all --force }
ECR 리포지토리에 저장된 이미지로 컨테이너 생성
docker container run --name hello-world -d -p 8080:3000 $ECR_REPO
컨테이너가 정상적으로 실행 되었는지 확인
curl -w "\n" localhost:8080
컨테이너 및 이미지 삭제
{ docker container rm hello-world --force docker image prune -a --force rm -rf ~/environment/express-hello-world aws ecr delete-repository --repository-name express-hello-world --force }
아래의 요구 사항에 맞게 컨테이너 이미지를 만들고 실행하세요.
Docker Hub에 있는 NGINX 이미지 사용
웹사이트 루트를 호출하면 Hello, Container가 표시어야 함
로컬호스트의 8080포트를 컨테이너에서 실행되는 NGINX 웹서버의 포트와 연동
이미지 경량화
데모 애플리케이션 소스코드 다운로드
cd ~/environment && git clone https://github.com/youngwjung/echo-hello-world.git && cd echo-hello-world
애플리케이션 구동
go run main.go
새로운 터미널을 열고 웹 애플리케이션이 구동하는지 확인
curl -w "\n" localhost:8080
기존 터미널로 돌아와서
Ctrl+C
를 입력해서 애플리케이션 정지Dockerfile 리뷰
컨테이너 이미지 빌드
docker image build -t echo-hello-world .
컨테이너 실행
docker container run --name hello-world -d -p 8080:8080 echo-hello-world
컨테이너가 정상적으로 실행 되었는지 확인
curl -w "\n" localhost:8080
컨테이너 삭제
docker container rm hello-world --force
컨테이너 이미지 크기 확인
docker image ls
멀티 스테이지로 짜여진 Dockerfile 리뷰
컨테이너 이미지 빌드
docker image build -t echo-hello-world:multistage . -f Dockerfile_multistage
컨테이너 이미지 크기 확인
docker image ls
새로운 이미지 빌드
cat <<EOF | docker image build -t boto3 - FROM python RUN apt update && apt install -y curl RUN useradd developer RUN pip install boto3 CMD ['python'] EOF
컨테이너 이미지 크기 확인
docker image ls boto3
14번 명령어에 명시된 Dockerfile을 수정해서 경량화된 이미지를 생성하세요.
컨테이너 네트워크
호스트에 있는 네트워크 인터페이스 목록 확인
ip a
컨테이너 생성
docker container run --name nginx -d nginx
컨테이너에 부여된 IP 확인
docker container inspect nginx --format '{{.NetworkSettings.IPAddress}}'
컨테이너에서 실행중인 NGINX 웹서버 호출
curl $(docker container inspect nginx --format '{{.NetworkSettings.IPAddress}}')
호스트에 있는 네트워크 인터페이스 목록 확인
ip a
컨테이너 안에 있는 네트워크 인터페이스 목록 확인
docker exec nginx ip a
컨테이너에 ip 프로그램 설치
{ docker container exec nginx apt update docker container exec nginx apt install iproute2 -y }
컨테이너 안에 있는 네트워크 인터페이스 목록 확인
docker exec nginx ip a
호스트에 있는 네트워크 인터페이스 목록 확인
ip a
컨테이너 로그 확인
docker logs nginx
컨테이너 삭제
docker container rm nginx --force
Docker 네크워크 목록 확인
docker network ls
컨테이너 재생성
docker container run --network host --name nginx -d nginx
컨테이너 안에 있는 네트워크 인터페이스 목록 확인
{ docker container exec nginx apt update docker container exec nginx apt install iproute2 -y docker container exec nginx ip a }
웹브라우저에서 Cloud9 인스턴스의 공인 IP로 접속되는지 확인 - 아래 명령어로 주소 확인 가능
echo "$(curl -s ifconfig.io)"
연결에 실패할 경우에는 아래의 명령어를 실행해서 보안그룹에 인바운드 규칙 추가
{ TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 60") aws ec2 authorize-security-group-ingress \ --group-id $(aws ec2 describe-security-groups \ --filters Name=group-name,Values=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/security-groups) \ --query "SecurityGroups[0].GroupId" --output text) \ --protocol tcp \ --port 80 \ --cidr 0.0.0.0/0 }
컨테이너 삭제
docker container rm nginx --force
컨테이너 재생성
docker container run --publish 8080:80 --name nginx -d nginx
웹브라우저에서 포트포워딩한 포트를 통해서 컨테이너로 접근되는지 확인 - 아래 명령어로 주소 확인 가능
echo "$(curl -s ifconfig.io):8080"
연결에 실패할 경우에는 아래의 명령어를 실행해서 보안그룹에 인바운드 규칙 추가
{ TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 60") aws ec2 authorize-security-group-ingress \ --group-id $(aws ec2 describe-security-groups \ --filters Name=group-name,Values=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/security-groups) \ --query "SecurityGroups[0].GroupId" --output text) \ --protocol tcp \ --port 8080 \ --cidr 0.0.0.0/0 }
Iptable의 모든 규칙 확인
sudo iptables-save
DOCKER 규칙 확인
sudo iptables -t nat -L DOCKER -n | column -t
컨테이너 삭제
docker container rm nginx --force
DOCKER 규칙 확인
sudo iptables -t nat -L DOCKER -n | column -t
컨테이너 재생성
docker container run --publish 127.0.0.1:8080:80 --name nginx -d nginx
웹브라우저에서 포트포워딩한 포트를 통해서 컨테이너로 접근되는지 확인 - 아래 명령어로 주소 확인 가능
echo "$(curl -s ifconfig.io):8080"
Loopback 주소로 접속 시도
curl localhost:8080
새로운 컨테이너 생성
docker container run --name busybox -d busybox sleep 3600
새로 생성한 컨테이너에서 NGINX 컨테이너에 접근이 되는지 확인
docker container exec busybox \ ping $(docker container inspect nginx --format '{{.NetworkSettings.IPAddress}}')
컨테이너 삭제
docker container rm busybox --force
새로운 Docker 네크워크 생성
docker network create --subnet 192.168.0.0/16 my_net
Docker 네크워크 목록 확인
docker network ls
위에서 생성한 Docker 네트워크를 사용하는 컨테이너 생성
docker container run --name client --network my_net -d praqma/network-multitool sleep 3600
새로 생성한 컨테이너에서 NGINX 컨테이너에 접근이 되는지 확인
docker container exec client \ curl -sv -m 3 $(docker container inspect nginx --format '{{.NetworkSettings.IPAddress}}')
새로 생성한 Docker 네트워크를 사용하는 Apache 컨테이너 생성
docker container run --name httpd --network my_net -d httpd
동일한 Docker 네트워크를 사용하는 컨테이너에서 Apache 컨테이너에 접근이 되는지 확인
docker container exec client \ curl -s $(docker container inspect httpd --format '{{.NetworkSettings.Networks.my_net.IPAddress}}')
컨테이너 이름으로 Apache 컨테이너에 접근이 되는지 확인
docker container exec client \ curl -s httpd
컨테이너 이름으로 도메인 주소 검색 시도
docker container exec client \ dig httpd
Apache 컨테이너의 IP 주소 확인
docker container inspect httpd \ --format '{{.NetworkSettings.Networks.my_net.IPAddress}}'
리소스 정리
{ docker container rm $(docker container ls -aq) --force docker image prune --all --force docker network rm my_net }
아래의 요구 사항에 맞게 컨테이너 이미지를 만들고 실행하세요.
Docker Hub에 있는
mysql:5.7
이미지 사용로컬호스트의 3366 포트를 컨테이너에서 실행되는 MySQL 데이터베이스의 포트와 연동
로컬호스트에서 아래의 명령어를 실행해서 DB에 접속
mysql -h 127.0.0.1 -P 3366 -u root -p
컨테이너 스토리지
리소스 정리
{ docker container rm $(docker container ls -aq) --force docker volume prune --force }
MySQL 컨테이너 생성
docker container run --name mysql -d -p 3306:3306 \ -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.7
데이터베이스 및 레코드 생성
mysql -h 127.0.0.1 -u root <<EOF CREATE DATABASE test; CREATE TABLE test.messages (message VARCHAR(250)); INSERT INTO test.messages VALUES ('hello'); EOF
위에서 생성한 데이터를 확인
mysql -h 127.0.0.1 -u root -e "SELECT message FROM test.messages;"
만약 MySQL 컨테이너를 삭제하면 위에서 생성한 데이터는 어떻게 되나요?
컨테이너 생성에 사용된 명령 및 메타데이터(Dockerfile에 명시된 내용) 확인
docker image history mysql:5.7 --format '{{.CreatedBy}}'
MySQL 컨테이너에 마운트된 볼륨 확인
docker container inspect mysql --format '{{json .Mounts}}' | jq
Docker 볼륨 목록 확인
docker volume ls
MySQL 컨테이너에 마운트된 볼륨 ID를 환경 변수로 저장
export MYSQL_VOL_ID=$(docker volume ls -q)
만약 MySQL 컨테이너를 삭제하고 재생성하면 위에서 생성한 데이터가 새로 생성된 컨테이너에 연동될까요?
MySQL 컨테이너 재생성
{ docker container rm mysql --force docker container run --name mysql -d -p 3306:3306 \ -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.7 }
데이터 확인
mysql -h 127.0.0.1 -u root -e "SELECT message FROM test.messages;"
Docker 볼륨 목록 확인
docker volume ls
MySQL 컨테이너 삭제
docker container rm mysql --force
MySQL 컨테이너 재생성
docker container run --name mysql -d -p 3306:3306 \ --mount source=$MYSQL_VOL_ID,target=/var/lib/mysql \ -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.7
데이터 확인
mysql -h 127.0.0.1 -u root -e "SELECT message FROM test.messages;"
MySQL 컨테이너 삭제
docker container rm mysql --force
Docker 볼륨 목록 확인
docker volume ls
사용하지 않는 볼륨 삭제
docker volume prune --force
Docker 볼륨 생성
docker volume create mysql
MySQL 컨테이너 생성
docker container run --name mysql -d -p 3306:3306 \ --mount source=mysql,target=/var/lib/mysql \ -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.7
MySQL 컨테이너에 마운트된 볼륨 확인
docker container inspect mysql --format '{{json .Mounts}}' | jq
리소스 정리
{ docker container rm $(docker container ls -aq) --force docker volume prune --force }
디렉토리 생성
mkdir -p $HOME/environment/nginx/html
HTML 문서 생성
echo "Hello, Docker" > $HOME/environment/nginx/html/index.html
NGINX 컨테이너 생성
docker container run --name nginx -d -p 8080:80 \ --mount type=bind,source=$HOME/environment/nginx/html,target=/usr/share/nginx/html \ nginx
NGINX 웹서버 호출
curl localhost:8080
HTML 문서에 내용 추가
echo "Hello, Volume" >> $HOME/environment/nginx/html/index.html
NGINX 웹서버 호출
curl localhost:8080
컨테이너의
/usr/share/nginx/html
경로에 있는 파일 확인docker container exec nginx ls /usr/share/nginx/html
컨테어너와 연동된 디렉토리에 새로운 파일 생성
touch $HOME/environment/nginx/html/new-file-from-host.txt
컨테이너의
/usr/share/nginx/html
경로에 있는 파일 확인docker container exec nginx ls /usr/share/nginx/html
컨테이너에서 호스트와 연동된 디렉토리에 새로운 파일 생성
docker container exec nginx touch /usr/share/nginx/html/new-file-from-container.txt
로컬호스트의
$HOME/environment/nginx/html
경로에 있는 파일 확인ls $HOME/environment/nginx/html
리소스 정리
{ docker container rm $(docker container ls -aq) --force rm -rf $HOME/environment/nginx }
아래의 요구 사항에 맞게 컨테이너 이미지를 만들고 실행하세요.
my-app 이라는 이름의 Docker 볼륨 생성
Docker 허브에 있는 NGINX 이미지로 컨테이너를 생성하고 위에서 생성한 my-app 볼륨을
/opt/app
경로에 마운트NGINX 컨테이너
/opt/app/
경로에 hello.txt 파일을 생성하고 내용으로 world를 추가Docker 허브에 있는 Apache 이미지로 컨테이너를 생성하고 위에서 생성한 my-app 볼륨을
/usr/app
경로에 마운트를 하되 읽기 권한만 부여Apache 컨테이너
/usr/app/
경로에 hello.txt 파일이 있는지 확인 하고 내용 확인Apache 컨테이너에서
/usr/app/hello.txt
파일을 열고 수정이 가능한지 확인
컨테이너 디버깅
리소스 정리
{ docker container rm $(docker container ls -aq) --force docker volume prune --force }
NGINX 컨테이너 생성
docker container run --name nginx -d nginx
컨테이너에서 프로세스를 실행하는 유저 확인
docker container exec nginx id
컨테이너에 생성되어 있는 유저 목록 확인
docker container exec nginx cat /etc/passwd
NGINX 컨테이너 삭제
docker container rm nginx --force
NGINX 컨테이너 재생성하고 nginx 유저로 프로세스 실행
docker container run --name nginx -d -u nginx nginx
실행중인 컨테이너 목록 확인
docker container ls
모든 컨테이너 목록 확인
docker container ls -a
NGINX 컨테이너 상태에 대한 상세 내용 확인
docker container inspect nginx --format '{{json .State}}' | jq
NGINX 컨테이너 로그 확인
docker container logs nginx
NGINX 컨테이너의 로그 파일이 저장되는 경로 확인
{ export NGINX_LOG_PATH=$(docker container inspect nginx --format '{{.LogPath}}') echo $NGINX_LOG_PATH }
로그 파일 내용 확인
sudo cat $NGINX_LOG_PATH
NGINX 컨테이너 삭제
docker container rm nginx --force
삭제된 컨테이너의 로그 파일이 남아 있는지 확인
sudo cat $NGINX_LOG_PATH
NGINX 컨테이너 재생성
docker container run --name nginx -d nginx
NGINX 컨테이너 환경에 bash 프로세스 실행
docker container exec -it nginx bash
NGINX 설정 파일 확인
cat /etc/nginx/nginx.conf
NGINX 프로세스의 PID 파일이 생성되는 경로의 권한 확인
ls -al /var/run
실행중인 프로세스 목록 확인
ps aux
실행중인 프로세스의 리소스 사용량 확인
top
bash 프로세스 종료
exit
NGINX 컨테이너에서 실행중인 프로세스 목록 확인
docker container top nginx
NGINX 컨테이너가 사용중인 리소스 사용량 확인
docker container stats nginx
새로운 컨테이너 생성
docker container run --name echo -d youngwjung/echo
컨테이너가 실행중인지 확인하고 실행중이지 않다면 어떤 이유인지 확인
컨테이너 로그 확인
docker container logs echo
컨테이너 로그에
Hello, Docker
가 출력되도록 컨테이너 생성docker container run --name hello-docker -d youngwjung/echo Hello, Docker
컨테이너 로그 확인
docker container logs hello-docker
컨테이너 로그에 현재 시간이 출력 되도록 컨테이너 생성
docker container run --name date -d --entrypoint date youngwjung/echo
컨테이너 로그 확인
docker container logs date
리소스 정리
{ docker container rm $(docker container ls -aq) --force docker volume prune --force docker image prune --all --force }
아래의 내용들을 수행해서 문제 해결
컨테이너 생성
docker container run --name file -d youngwjung/docker-lab:file
컨테이너 안에
/app/password.txt
파일의 내용을 확인새로운 컨테이너 생성
docker container run --name env -d youngwjung/docker-lab:env
애플리케이션 로그 파일을 참고해서 애플리케이션이 정상적으로 실행되고 종료되도록 설정 애플리케이션이 정상 실행/종료되면 애플리케이션 로그를 통해서 다음 단계에서 필요한 정보를 확인 가능
새로운 컨테이너 생성
docker container run --name port -d youngwjung/docker-lab:port
TCP 서버가 구동중이고 이전 단계에서 확인한 암호를 TCP 서버로 전송하게 되면 다음 단계에서 필요한 정보를 확인 가능
새로운 컨테이너 생성
docker container run --name copy -d youngwjung/docker-lab:copy
컨테이너 안에
/message.txt.gpg
파일이 GPG를 통해서 암호화 되어있습니다. 파일 내용을 확인하세요.
Last updated