# 도커 무작정 따라하기 도커 무작정 따라하기: 도커가 처음인 사람도 60분이면 웹 서버를 올릴 수 있습니다! - https://hub.docker.com/ 출처: https://www.slideshare.net/pyrasis/docker-fordummies-44424016 ## 도커의 특징 ### 도커의 성능 - 도커는 하드웨어 가상화 계층이 없음 - 메모리 접근, 파일 시스템, 네트워크 전송 속도가 가상 머신에 비해 월등히 빠름 ### 도커의 특징 이미지 버전 관리도 제공하고 중앙 저장소에 이미지를 올리고 받을 수 있음 (push/pull) GitHub와 비슷한 형태로 도커 이미지를 공유하는 Docker Hub 제공 (GitHub처럼 유료 저장소도 제공) 다양한 API를 제공하여 원하는 만큼 자동화 가능, 개발과 서버 운영에 매우 유용! ### 가상 머신의 문제점 그런데 이미지와 컨테이너는 뭐가 다른 거지? ## 도커 이미지와 컨테이너 ### 도커 이미지 이미지는 서비스 운영에 필요한 서버 프로그램, 소스 코드, 컴파일된 실행 파일을 묶은 형태 저장소에 올리고 받는건 이미지 (push/pull) 컨테이너는 이미지를 `실행한 상태!` 이미지로 여러 개의 컨테이너를 만들 수 있음 운영체제로 치면 `이미지는 실행파일`이고 `컨테이너는 프로세스` ### 도커의 이미지 처리 방식 도커는 이미지의 바뀐 부분을 어떻게 관리하나? 유니온 파일 시스템 형식 (aufs, btrfs, devicemapper) ![](https://i.imgur.com/KEy1y8S.png) - 도커는 베이스 이미지에서 바뀐 부분만 이미지로 생성 - 컨테이너로 실행할 때는 베이스 이미지와 바뀐 부분을 합쳐서 실행 - Docker Hub 및 개인 저장소에서 이미지를 공유할 때 바뀐 부분만 주고 받음 - 각 이미지는 `의존 관계` 형성 ## 서비스 운영 환경과 도커 ### 지금까지의 서버 환경 - 지금까지는 물리 서버를 직접 운영 했음 - 호스팅 또는 IDC 코로케이션 서비스 사용 - 서버 구입과 설치에 돈이 많이 들고 시간이 오래 걸림 ### 클라우드 환경 - 가상화가 발전하면서 `클라우드 환경으로 변환` - 가상 서버를 `임대`하여 사용한 만큼만 `요금 지불` - 클릭 몇 번 만으로 가상 서버를 생성 - 이젠 자동으로 서버를 추가하고 삭제하기까지... - 서버 대수가 많아지면서 사람이 일일이 세팅하기 힘들어짐 - 이제 서버 세팅과 배포는 어떻게? ### Immutable Infrastructure - `Immutable Infrastructure`라는 패러다임이 나옴 - 호스트 OS와 서비스 운영 환경(서버 프로그램, 소스코드, 컴파일된 바이너리)을 `분리` - 한 번 설정한 운영 환경은 `변경하지 않는다(Immutable)`는 개념 ![](https://i.imgur.com/6kzybPZ.png) - 서비스 운영 환경을 `이미지로 생성`한 뒤 `서버에 배포하여 실행` - 서비스가 업데이트되면 운영 환경 자체를 변경하지 않고, `이미지를 새로 생성하여 배포` - 클라우드 플랫폼에서 서버를 쓰고 버리는 것과 같이 Immutable Infrastructure도 `서비스 운영 환경 임지를 한 번 쓰고 버림` - 도커는 Immutable Infrastructure를 구현한 프로젝트 #### 편리한 관리 - 서비스 환경 `이미지만 관리`하면 됨 - 중앙 관리를 통한 `체계적인 배포와 관리` - 이미지 생성에 `버전 관리 시스템 활용` #### 확장 - 이미지 하나로 `서버를 계속 찍어낼 수 있음` - 클라우드 플랫포의 자동 확장(Auto Scaling) 기능과 연동하여 `손쉽게 서비스 확장` #### 테스트 - 개발자 PC, 테스트 서버에서 이미지를 실행만 하면 서비스 운영 환경과 `동일한 환경이 구성됨` - 테스트가 간편 #### 가볍다 - 운영체제와 서비스 환경을 `분리`하여 가볍고(Lightweight) 어디서든 실행 가능한(Portable) 환경 제공 ## 도커 요약 ![컨테이너를 싣고 다니는 고래](https://i.imgur.com/oW02sIo.png) - 고래는 서버에서 여러 개의 컨테이너(이미지)를 `실행`하고 이미지 `저장과 배포(운반)`를 의미 - 도커(Docker)는 부두 노동자를 뜻함 컨테이너를 다루는 도커의 기능과 비슷함 - 도커는 서비스 운영 환경을 묶어서 손쉽게 배포하고 실행하는 `경량 컨테이너` 기술 ## 도커 설치하기 공식문서 ⇒ https://docs.docker.com/install/linux/docker-ce/ubuntu/ 도커 레파지토리를 추가 ``` # gedit /etc/apt/sources.list deb https://apt.dockerproject.org/repo ubuntu-xenial main ``` HTTPS 통신에 사용되는 패키지와 공개키를 설치 ``` # apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common ``` ``` # apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D ``` linux-image extra와 docker-engine 패키지를 설치 ``` sudo apt-get update # apt-get install linux-image-extra-$(uname -r) # apt-get install docker-engine ``` ``` root@server:~# docker version Client: Version: 17.05.0-ce API version: 1.29 Go version: go1.7.5 Git commit: 89658be Built: Thu May 4 22:10:54 2017 OS/Arch: linux/amd64 Server: Version: 17.05.0-ce API version: 1.29 (minimum version 1.12) Go version: go1.7.5 Git commit: 89658be Built: Thu May 4 22:10:54 2017 OS/Arch: linux/amd64 Experimental: false ``` main.go 파일 작성 ``` package main import ( "fmt" "log" "net/http" ) func main(){ http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){ log.Println("received request") fmt.Fprintf(w, "Hello Docker !!!") }) log.Println("start server") server := &http.Server{Addr: ":8000"} if err := server.ListenAndServe(); err != nil { log.Println(err) } } ``` 설치 ``` # apt install golang-go # go run main.go ``` ### DockerFile 생성 ``` root@server:~/docker# gedit Dockerfile ``` ``` FROM golang:1.9 RUN mkdir /echo COPY main.go /echo CMD [ "go", "run", "/echo/main.go" ] ``` ### docker ```shell docker image --help docker image build --help root@server:~/docker# docker image build -t example/echo:latest . ``` - `-t` 는 이미지 이름:태그 이미지 목록 확인 ```shell root@server:~/docker# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE example/echo latest e5bf61deed81 2 minutes ago 750MB golang 1.9 ef89ef5c42a9 10 months ago 750MB ``` ```shell root@server:~/docker# docker image ls -a REPOSITORY TAG IMAGE ID CREATED SIZE b4ba25ac2cae 3 minutes ago 750MB example/echo latest e5bf61deed81 3 minutes ago 750MB 58f3cb19c839 3 minutes ago 750MB golang 1.9 ef89ef5c42a9 10 months ago 750MB ``` ### 이미지 내용 변경 내용 변경 후 이미지 다시 만들기 ```shell root@server:~/docker# docker image build -t example/echo:latest . Sending build context to Docker daemon 3.072kB Step 1/4 : FROM golang:1.9 ---> ef89ef5c42a9 Step 2/4 : RUN mkdir /echo ---> Using cache ---> 58f3cb19c839 Step 3/4 : COPY main.go /echo ---> b812938cbabc Removing intermediate container c91757d70919 Step 4/4 : CMD go run /echo/main.go ---> Running in 5e76624a9714 ---> 133a6f8f5426 Removing intermediate container 5e76624a9714 Successfully built 133a6f8f5426 Successfully tagged example/echo:latest root@server:~/docker# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE example/echo latest 133a6f8f5426 46 seconds ago 750MB e5bf61deed81 8 minutes ago 750MB golang 1.9 ef89ef5c42a9 10 months ago 750MB ``` ### 도커 이미지 실행 ```shell root@server:~/docker# docker container run -p 9000:8000 -d example/echo:latest 25bdbb71d2591730d259c7dcb07da0557add80a9ba70e96753c907b462d4b704 ``` ```shell root@server:~/docker# docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 25bdbb71d259 example/echo:latest "go run /echo/main.go" 2 hours ago Up 2 hours 0.0.0.0:9000->8000/tcp thirsty_goldstine ``` - 이름을 줄 수 있다. ### 컨테이너 하나 더 실행 ```shell root@server:~/docker# docker container run -p 9001:8000 -d example/echo:latest 5a140cf82ca1112164487268e2b2d161a84a725aa5d5af5247a2e711725c9032 root@server:~/docker# docker container ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5a140cf82ca1 example/echo:latest "go run /echo/main.go" 6 seconds ago Up 4 seconds 0.0.0.0:9001->8000/tcp priceless_shockley 25bdbb71d259 example/echo:latest "go run /echo/main.go" 2 hours ago Up 2 hours 0.0.0.0:9000->8000/tcp thirsty_goldstine ``` ### 컨테이너 삭제 ```shell root@server:~/docker# docker container rm 5a Error response from daemon: You cannot remove a running container 5a140cf82ca1112164487268e2b2d161a84a725aa5d5af5247a2e711725c9032. Stop the container before attempting removal or force remove root@server:~/docker# docker container rm -f 5a 5a root@server:~/docker# docker container rm -f 25 25 root@server:~/docker# docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ``` `-f` 옵션으로 강제 종료 ### 컨테이너 id 조회 ```shell root@server:~/docker# docker container ps -q 4ad6c2a7994c d08c882043e6 ``` ```shell docker container rm -f $(docker container ps -q) ``` ### attach 를 위한 옵션 ```shell root@server:~/docker# docker container run -it -p 9000:8000 -d example/echo:latest /bin/bash 9ec1ad3c49f00164195eb7872ab0600f58a5cf58079e566a84bb1e83f253f714 root@server:~/docker# docker attach 9e root@9ec1ad3c49f0:/go# ``` 종료 ```shell root@9ec1ad3c49f0:/echo# exit exit root@server:~/docker# docker container ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES root@server:~/docker# docker container ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9ec1ad3c49f0 example/echo:latest "/bin/bash" 7 minutes ago Exited (127) 3 minutes ago infallible_joliot ``` 다시 실행 ```shell root@server:~/docker# docker container restart 9e 9e root@server:~/docker# docker container ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9ec1ad3c49f0 example/echo:latest "/bin/bash" 9 minutes ago Up 3 seconds 0.0.0.0:9000->8000/tcp infallible_joliot ``` stop ```shell root@server:~/docker# docker container stop 9e 9e root@server:~/docker# docker container ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9ec1ad3c49f0 example/echo:latest "/bin/bash" 11 minutes ago Exited (0) 2 seconds ago infallible_joliot ``` ### 컨테이너 실행 ```shell root@server:~/docker# docker container run -it -p 9000:8000 --name echo1 -d example/echo:latest e2c45c8b92f9c2196b9fbc2bcca10b777384e6ab3f332778116a350ce41bb97e root@server:~/docker# docker container run -it -p 9001:8000 --name echo2 -d example/echo:latest 0371d5eb3d1ed93dfb7408266775781dcdac37e5113b3074d9d43262f2200d6f root@server:~/docker# docker container ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0371d5eb3d1e example/echo:latest "go run /echo/main.go" 8 seconds ago Up 7 seconds 0.0.0.0:9001->8000/tcp echo2 e2c45c8b92f9 example/echo:latest "go run /echo/main.go" 48 seconds ago Up 47 seconds 0.0.0.0:9000->8000/tcp echo1 ``` nginx ```shell root@server:~/docker# docker container run -d -p 9003:80 --name web2 nginx fd906f33ad9133796809583f31b275685971dcc82d81a437ecda97a46ea4511b ``` ```shell root@server:~/docker# docker container ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fd906f33ad91 nginx "nginx -g 'daemon ..." 2 minutes ago Up 2 minutes 0.0.0.0:9003->80/tcp web2 e6eb11fb9666 nginx "nginx -g 'daemon ..." 6 minutes ago Exited (0) 4 minutes ago web1 0371d5eb3d1e example/echo:latest "go run /echo/main.go" 7 minutes ago Up 7 minutes 0.0.0.0:9001->8000/tcp echo2 e2c45c8b92f9 example/echo:latest "go run /echo/main.go" 8 minutes ago Up 8 minutes 0.0.0.0:9000->8000/tcp echo1 9ec1ad3c49f0 example/echo:latest "/bin/bash" 42 minutes ago Exited (0) 30 minutes ago infallible_joliot ``` ### 컨테이너 검색 ```shell root@server:~/docker# docker container ps --filter "ancestor=example/echo" CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0371d5eb3d1e example/echo:latest "go run /echo/main.go" 9 minutes ago Up 9 minutes 0.0.0.0:9001->8000/tcp echo2 e2c45c8b92f9 example/echo:latest "go run /echo/main.go" 10 minutes ago Up 10 minutes 0.0.0.0:9000->8000/tcp echo1 ``` ```shell root@server:~/docker# docker container ps -a --filter "ancestor=example/echo" CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0371d5eb3d1e example/echo:latest "go run /echo/main.go" 10 minutes ago Up 10 minutes 0.0.0.0:9001->8000/tcp echo2 e2c45c8b92f9 example/echo:latest "go run /echo/main.go" 11 minutes ago Up 11 minutes 0.0.0.0:9000->8000/tcp echo1 9ec1ad3c49f0 example/echo:latest "/bin/bash" 44 minutes ago Exited (0) 32 minutes ago infallible_joliot ``` ### 기본 명령어 docker image - build : Dockerfile -> Image 생성 - pull : library/nginx:latest - push : [myid]/ - docker login 후에 push docker container run [image_name] - -d : detach - -it : interaction - -p : port forwarding - --name : 이름 지정 docker container stop [container_id] docker container restart docker container rm - -f : 강제 삭제 ### 이미지 올리기 ```shell root@server:~/docker# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE example/echo latest 133a6f8f5426 3 hours ago 750MB e5bf61deed81 3 hours ago 750MB nginx latest 53f3fd8007f7 3 weeks ago 109MB golang 1.9 ef89ef5c42a9 10 months ago 750MB ``` ```shell root@server:~/docker# docker image tag example/echo:latest jacegem/echo:latestroot@server:~/docker# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE example/echo latest 133a6f8f5426 3 hours ago 750MB jacegem/echo latest 133a6f8f5426 3 hours ago 750MB e5bf61deed81 3 hours ago 750MB nginx latest 53f3fd8007f7 3 weeks ago 109MB golang 1.9 ef89ef5c42a9 10 months ago 750MB ``` ```shell root@server:~/docker# docker image push jacegem/echo:latest The push refers to a repository [docker.io/jacegem/echo] 1542d130dabd: Pushed da8b71e70fad: Pushed 186d94bd2c62: Mounted from library/golang 24a9d20e5bee: Mounted from library/golang e7dc337030ba: Mounted from library/golang 920961b94eb3: Mounted from library/golang fa0c3f992cbd: Mounted from library/golang ce6466f43b11: Mounted from library/golang 719d45669b35: Mounted from library/golang 3b10514a95be: Mounted from library/golang latest: digest: sha256:d30f59e7e31708f73d8fcf21f301b6bc46ac0ad8669703e2d305e4bd3c9043cf size: 2417 ``` ```shell root@server:~/docker# docker image pull myanjini/echo Using default tag: latest latest: Pulling from myanjini/echo 55cbf04beb70: Already exists 1607093a898c: Already exists 9a8ea045c926: Already exists d4eee24d4dac: Already exists 9c35c9787a2f: Already exists 8b376bbb244f: Already exists 0d4eafcc732a: Already exists 186b06a99029: Already exists c6f2dfa6c4bc: Pull complete 0ef374528dd6: Pull complete Digest: sha256:349156f17a9f55e548bff2dc2301be0e4937506b25464a1e9a401f1f39728fe5 Status: Downloaded newer image for myanjini/echo:latest ``` ![](https://i.imgur.com/9nXWSe2.png) ![](https://i.imgur.com/kRLurgK.png) http://70.12.50.160:9500 ```shell root@server:/var/www/html# docker container ls -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 59aff7e41078 example/echo "go run /echo/main.go" 15 seconds ago Created angry_bhaskara fd906f33ad91 nginx "nginx -g 'daemon ..." 2 hours ago Up 2 hours 0.0.0.0:9003->80/tcp web2 e6eb11fb9666 nginx "nginx -g 'daemon ..." 2 hours ago Exited (0) 2 hours ago web1 0371d5eb3d1e example/echo:latest "go run /echo/main.go" 2 hours ago Up 2 hours 0.0.0.0:9001->8000/tcp echo2 e2c45c8b92f9 example/echo:latest "go run /echo/main.go" 2 hours ago Up 2 hours 0.0.0.0:9000->8000/tcp echo1 9ec1ad3c49f0 example/echo:latest "/bin/bash" 2 hours ago Exited (0) 2 hours ago infallible_joliot root@server:/var/www/html# docker container stop e2 e2 root@server:/var/www/html# docker container run -d -p 9000:8000 example/echo 400484c6af559d31ec5235f02dc56f0f2a840d903748bd34f14573dbb0accd76 ``` ```shell root@server:~/docker# docker container exec 40 ls /echo main.go root@server:~/docker# docker container rm -f $(docker container ls -a -q) 400484c6af55 59aff7e41078 fd906f33ad91 e6eb11fb9666 0371d5eb3d1e e2c45c8b92f9 9ec1ad3c49f0 ``` ```shell root@server:~/docker# docker system prune WARNING! This will remove: - all stopped containers - all volumes not used by at least one container - all networks not used by at least one container - all dangling images Are you sure you want to continue? [y/N] y Total reclaimed space: 0B ``` ```shell root@server:~/docker# docker container run -d -p 9000:80 nginx Unable to find image 'nginx:latest' locally latest: Pulling from library/nginx 743f2d6c1f65: Pull complete 6bfc4ec4420a: Pull complete 688a776db95f: Pull complete Digest: sha256:23b4dcdf0d34d4a129755fc6f52e1c6e23bb34ea011b315d87e193033bcd1b68 Status: Downloaded newer image for nginx:latest 862795b066d8425bf832e9fce88e0566789b6c196517b945cf2b6b19913a2b2b root@server:~/docker# docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 862795b066d8 nginx "nginx -g 'daemon ..." 23 seconds ago Up 21 seconds 0.0.0.0:9000->80/tcp hardcore_brattain ``` ```shell root@server:~/docker# docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 862795b066d8 nginx "nginx -g 'daemon ..." 23 seconds ago Up 21 seconds 0.0.0.0:9000->80/tcp hardcore_brattain root@server:~/docker# docker container exec 86 ls /usr/share/nginx/html 50x.html index.html ``` ```shell root@server:~/docker# docker container cp 86:/usr/share/nginx/html/index.html . root@server:~/docker# ls Dockerfile index.html main.go ``` ```shell root@server:~/docker# docker container cp ./index.html 86:/usr/share/nginx/html/index.html ``` ### 자동 설치 스크립트 도커는 리눅스 배포판 종류를 자동으로 인식하여 도커 패키지를 설치해주는 스크립트를 제공 ```shell $ sudo wget -qO- https://get.docker.com | sh ``` - get.docker.com 스크립트로 도커를 설치하면 hello-world 이미지도 자동 설치됨 - hello-world 이미지는 사용하지 않을 것이므로 모두 삭제 ```shell $ sudo docker rm `sudo docker ps -aq` $ sudo docker rmi hello-world ``` ### 우분투 - 자동 설치 스크립트를 사용하지 않고 우분투에서 직접 설치하기 - 버전은 14.04 LTS 64비트 기준 ```shell $ sudo apt-get update $ sudo apt-get install docker.io $ sudo ln -sf /usr/bin/docker.io /usr/local/bin/docker ``` /usr/bin/docker.io 실행 파일을 /usr/local/bin/docker 로 링크하여 사용 ### Redhat Enterprise Linux, centos - 자동 설치 스크립트를 사용하지 않고 레드햇 엔터프라이즈 리눅스(RHEL) 와 centos에서 패키지로 직접 설치 하기 - RHEL과 CentOS 6 패키지 저장소에 docker-io가 없으므로 EPEL(Fedora Extra Packages For Enterprise Linux) 저장소를 사용할 수 있도록 설정 ```shell $ sudo yum install http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6.8.noarch.rpm $ sudo yum install docker-io ``` - AWS EC2에 설치되는 Amazon Linux(RHEL 기반)는 EPEL 저장소를 바로 사용할 수 있으므로 epel-release-6.8.noarch.rpm을 설치하지 않아도 됨 - centos 7 에서는 docker 패키지를 설치 CentOS 7 ```shell $ sudo yum install docker ``` Docker 서비스 실행하기 ```shell $ sudo service docker start ``` 부팅했을 때 자동으로 실행하기 ```shell $ sudo chkconfig docker on ``` ### 최신 바이너리 사용하기 - 배포판 버전이 오래되었거나, centOS 같이 버전업이 보수적인 배포판에서는 도커 패키지 버전이 낮은 경우가 있음 - 배포판 별 패키지가 아닌 빌드 된 바이너리를 직접 사용하는 방법 이미 패키지로 설치했을 때 ```shell $ sudo service docker stop $ sudo wget http://get.docker.com/builds/Linux?x86_64/docker-latest -O $(type -P docker) $ sudo service docker start ``` 새로 설치할 때 ```shell $ wget https://get.docker.com/builds/Linux/x86_4/docker-latest $ chmod +x docker-latest $ sudo mv docker-latest /usr/local/bin/docker $ sudo /usr/local/bin/docker -d ``` URL을 docker-latest로 지정하면 가장 최신 버전을 받고, docker-1.3.0처럼 지정하면 특정 버전을 받음 ## 도커 사용해보기 ### 도커 명령 ![](https://i.imgur.com/rPCrmfv.png) - 도커의 명령은 `docker <명령>` 형식 - 예) docker run, docker push - 항상 root 권한으로 실행 ### Search 명령으로 이미지 검색하기 ```shell # docker search <이미지 이름> $ sudo docker search ubuntu ``` - 보통 ubuntu, centos, redis 등 OS 나 프로그램 이름을 가진 이미지가 공식 이미지 - 나머지는 사용자들이 만들어서 공개한 이미지 - 도커는 Docker Hub(https://registry.hub.docker.com)를 통해 이미지를 공유하는 생태계가 구축되어 있음