Docker 다시한번 살펴보자.

2019. 6. 6. 08:12OS/개발환경구축

새로운 환경에서 일을 시작하게 되면서, 가장 우선 뭘 준비해볼까 생각을 좀 했다.

이젠 필수가 되어버린 Docker!!! 

자연스럽고 쉽게 사용해보기 위해선 백문이 불여일타!!

항상 시작은 Get Started부터 점차 범위를 늘려보도록 하자.

 

Enterprise Container Platform for High-Velocity Innovation :
Securely build, share and run any application, anywhere 

https://www.docker.com/

 

1. Get Started with Docker 

 

새로운 어플리케이션을 빌드하고 배포하는 것은 Container와 함께 하면 아주 빠르지요.

Docker Container는 실행에 필요한 코드, 런타임, 시스템 툴들과 라이브러리 등 모든 것이 포함된 

소프트웨어 개발 용도로 소프트웨어와 그것에 종속성을 표준화된 단위로 싸여져 있습니다.

어플리케이션이 항상 동일하게 실행되고, Container 이미지를 공유하는 것 만큼 쉽게 협업하는 것을 보장합니다.

Docker Container는 윈도우즈던 리눅스던 간에 Docker 툴과 API를 제공하고, 보다 나은 소프트웨어를 구축하지요.

 

  • 신속한 실행환경(on-board faster)과 개발 환경 설정하는 시간 낭비를 막아줍니다.
    새로운 인스턴스를 띄우고, 로컬에서 동작하는 제품 코드의 복사본을 만들어 줍니다.

  • 어플리케이션간의 충돌의 걱정없이  어떤 언어나 스택 또는 툴을 사용 할수 있는 폴리그랏 개발이 가능합니다.

  • 환경 불일치(environment inconsistencies)와 "나의 장비에서 동작하는" 문제는 독립된 Container 안의 어플리케이션, configs, 종속성등을 패키징을 통해 제거합니다.

  • 어플리케이션 보안에 대한 우려를 완화합니다.

 

(1) Docker Identification

 

시작하려면 Docker ID가 필요하다고 하니까, 만들어야죠.

 

(2) Download, Docker Desktop

 

Docker Desktop 부터 설치합시다.
Container화된 어플리케이션을 구축중인 수백만 개발자들에게 선호된 선택을 받았다고 하니 고고!

로컬 환경에 설치를 할것이고, 제 컴은 Windows 10 pro 입니다. 

https://hub.docker.com/?overlay=onboarding

 

(3) Sample Source Clone with Git

 

모든 작업은 로컬에서 진행하니, 리눅스 서버가 아닌 관계로 Windows PowerShell에서 진행하도록 합니다.

이 저장소는 첫번째 Docker Container를 생성하는데 필요한 모든것을 포함하고 있습니다.

 github에서 아래 예제를 복제합시다.

 

> git clone https://github.com/docker/doodle.git

 

 

Git: Git이 처음이라면 설치부터 하시고, 이름하고 이메일정도는 먼저 등록해주세요

  • Downlad :  https://git-scm.com/downloads

  • username & email : 

    • git config --global user.name "내이름"

    • git config --global user.email "이메일주소"

 

(4) Build & Tag your docker image

 

Docker image는 Container를 위한 개인 전용 파일 시스템입니다.

Container에서 필요로 하는 모든 코드와 파일을 이 Docker Image에서 제공합니다.

Docker build 명령을 실행하는 것은 Dockerfile를 사용해서 Docker image를 생성하는 것입니다.

이 빌드된 이미지는 여러분의 머신의 로컬 Docker image repository안에 있습니다.

 

> cd doodle\cheers2019

> docker build -t ksh4602/cheers2019 .

 

(5) Run your first docker container

 

Container를 실행하는 것은 로컬 머신의 일부분으로부터 안전히 독립되어,

개인 전용 리소스에 함께 소프트웨어를 실행하는 것이랍니다.

 

> docker run -it --rm ksh4602/cheers2019

 

 

(6) Ship your image on Docker hub

 

공유할 준비가 되었다면, Docker hub에 이미지를 푸쉬하시면 됩니다.

 

> docker login ;

> docker push ksh4602/cheers2019

 

 

여기까지 진행했다면, Docker Desktop 과 Docker Hub 설치및 실행까지 확인을 성공적으로 마친것이죠.

https://hub.docker.com/r/ksh4602/cheers2019

좀더 알아보고자 한다면,  Play with Docker Classroom: https://training.play-with-docker.com/ 을 참고

 

 

 

 

2. What is Docker?

 

워낙 잘 설명된 블로그 글들이 많다. 

정말 자세히 잘 나와 있으니 꼭 참고하도록 한다. 

아직 전체를 다 읽어보진 못한 상태이며, 계속 시간을 내어 읽어볼 예정이다.

 

 

 

 

3. Docker API

 

이제 자주 흔하게 사용하는 Docker 명령들을 살펴보도록 하자. 
CLI($ docker)는 API를 통해 Dockerd에 /var/run/docker.sock 을 통해서 명령을 전송한다고 한다.

 

진행은 Docker는 Docker hub를 통해 public Docker image Repository를 지원하고 있는 여러 이미지들을 가지고 Docker 명령어를 사용해 보도록 하자.

만약 private docker registry를 운영하게 된다면, AWS의 ECR(Elastic Container Registry) 

또는 Github Package Registry가 Beta Service 중이니 잘 지켜 보도록 하자

 

(1) help

> docker help 

 

뭐 이거 하나면 아래와 같이 정리할 필요가 있을까? 싶다. 알다시피 help에 모든게 다 들어 있다.

하지만 자주 사용하는 명령어들 위주로 정리가 필요하니 계속 진행 하자.

 

(2) search : Search the Docker Hub for images

https://docs.docker.com/engine/reference/commandline/search/

> docker search [이미지명] 

> docker search rabbitmq

 

어떤 이미지들이 있는지 찾아보는 것이 기본이겠다.  여기선 RabbitMQ를 찾아보자.

 

(3) run : Run a command in a new container 

https://docs.docker.com/engine/reference/commandline/run/

> docker run hello-world

> docker run hello-world:lastest

> docker run rabbitmq

> docker run --name=hello hello-world

> docker run -d -p 3306:3306 -e MYSQL_ALLOW_EMPTY_PASSWORD=true --name mysql mysql:5.7

 

run명령은 Container 이름이 중복되지 않는 이상 같은 이미지더라도 새롭게 Container를 생성합니다.

만약 위와 같이 동일한 이름으로 재실행하면 실행할수 없다는 것이죠

 

run 명령으로 rabbitmq 이미지가 로컬 저장소에 있는지 확인하고, 있다면 Cotainer로 실행하게 된다.

만약 없으면,원격 저장소에서 찾아주는 것까지 해준다. (pull 명령이 포함되어 있다는 것)

태그가 없을 경우에는 latest 가 기본이 된다.

위와 같이 실행했을 땐, 그냥 rabbitmq가 임의의 컨테이너 이름을 갖고 실행까지 하게 된다. 

이젠 좀 더 옵션을 붙여서 실행해보자

 

> docker run -d --hostname my-rabbitmq --name some-rabbit rabbitmq:3

 

  • -d (detach) : Container를 백그라운드로 실행하라는 옵션이다.

    위에까지 하게 되면, 5672 기본 포트로 리스닝하고 있을 것이다.

    management plugin을 세팅하게되면, http://container-ip:15672 에 접근이 가능하게 될것이다.

    계정은 guest / guest 이고, host 밖에서 접근하려면, 아래와 같이 하면 된다.

    뭐 그밖에 설정들을 위해서는  https://hub.docker.com/_/rabbitmq/ 에서 찾아서 진행해보면 될것 같다.

 

> docker run -d --hostname my-rabbit --name some-rabbit -p 5672:5672 -p 15672:15672 rabbitmq:3-management

> docker run -d --hostname my-rabbit --name some-rabbit rabbitmq:3-management

 

 

(4) inspect : return low-level information on Docker Object

https://docs.docker.com/engine/reference/commandline/inspect/

> docker inspect some-rabbit

> docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' some-rabbit

 

사실 container ip 정보를 알아내기 위해서 검색을 했던 것이다.

 

 

(5)  logs : fetch the logs of a container

https://docs.docker.com/engine/reference/commandline/logs/

> docker logs my-demo

> docker logs some-rabbitmq

> docker logs some-rabbitmq -f

 

 

로그를 확인하면 되고, -f  (follow)옵션은 실시간 로그 확인을 위해 붙여주면 되겠다.

 

 

(6) pull : pull an image or a repository from a registry

https://docs.docker.com/engine/reference/commandline/pull/

> docker pull hello-world

> docker pull ksh4602/nginx:0.1

> docker image pull rabbitmq

 

앞서 설명이 된 내용인 pull은 , 원격 저장소에서 로컬 저장소로 Docker  image를 가져오는 것이다.

 

 

(7) images : List images

https://docs.docker.com/engine/reference/commandline/images/

> docker images

> docker image ls

 

이미지들을 조회할 때 사용하는 것이다.

 

 

(8) ps :  List containers

https://docs.docker.com/engine/reference/commandline/ps/

> docker ps -a -s 

 

run이 Container를 만들고 실행하면, ps는 Container 리스트를 보여줍니다.

옵션 -a를 붙이면 실행, 중지(중지된 상태는 Exited)된 Container 전부 보여주고, 안붙이면 실행중인 Container만 보여줍니다.

 

(9) rm : Remove one or more containers

https://docs.docker.com/engine/reference/commandline/rm/

> docker rm elated_curran

> docker rm $(docker ps -a -q)

 

Container을 삭제할 때 사용하는 것입니다. 

뭐 두번째꺼는 중지된 모든 컨테이너를 제거하는 거죠.

 

(10) rmi : Remove one or more images

https://docs.docker.com/engine/reference/commandline/rmi/

> docker rmi hello

> docker rmi test1:latest

 

Container를 삭제하지 않고, 이미지를 삭제하면 충돌이 발생한다고 나옵니다.

 

(11) commit : Create a new image from a container's changes 

https://docs.docker.com/engine/reference/commandline/commit/

> docker commit -a "dennis@sptek.co.kr" -m "first commit on SPtek" "some-rabbit ksh4602/nginx:0.1

 

  • -a 작성자명 

  • -m 커밋 메시지

  • Container 이름

  • [만들 이미지이름]:tag   

말그대로 변경된 Container를 이미지로 저장하는 거죠.

 

(12) push : Push an image or a repository to a registry

https://docs.docker.com/engine/reference/commandline/push/

> docker push ksh4602/nginx:0.1

 

Docker Hub registry나 self-hosted registry에 이미지를 공유하는 것입니다.

 

(13) Stop/Start/Restart one or more running containers

https://docs.docker.com/engine/reference/commandline/stop/

https://docs.docker.com/engine/reference/commandline/start/

https://docs.docker.com/engine/reference/commandline/restart/

> docker status some-rabbit

> docker start some-rabbit

> docker restart some-rabbit

 

 

(14) stats :  Display a live stream of container(s) resource usage statistics

https://docs.docker.com/engine/reference/commandline/stats/

> docker stats some-rabbit

 

 

(15) diff : inspect changes to files or directories on a container's filestream

> docker diff some-rabbit

 

 

(16) exec : Run ja command in a running container

https://docs.docker.com/engine/reference/commandline/exec/

> docker exec -it mysql mysql -h localhost -uroot

 

 

 

4. 예제를 통해 Docker를 좀더 익숙해지기

 

앞서 참조 블로그(https://www.bsidesoft.com/?p=7851)에 잘 나온 예시를  그대로 진행해봅니다.

도움이 되니, 해당 블로그 글을 참고하면 좋을 것 같습니다.

 

(1) Nginx Container 실행하기

> docker run -d -p 7070:80 --name=my-nginx -v D:\docker_container\nginx:/usr/share/nginx/html nginx

 

  • -d : detach 옵션, Container를 백그라운드로 실행후 Container ID를 출력합니다.

  • -p 8080:80 : 포트번호를 바인딩(앞의 8080은 외부에 노출되는 포트번호 이며, 뒤의 80은 내부에서 쓰는 포트) 

  • -v : volumn 옵션, Container 볼륨을 host 볼륨과 연결하는 옵션입니다. 

    • -v D:\docker_container\nginx:/usr/share/nginx/html 옵션을 줬다면

    • 앞의 /D/nginx/html 은 현재 호스트의 볼륨(D:드라이버에 /nginx/html 폴더)를 의미함.

    • 뒤의 /usr/share/nginx/html는 Container의 볼륨을 의미합니다.

    • 나중에 Container가 삭제되더라도 이렇게 지정된 볼륨은 삭제되지 않으며 새로운 Container를 실행할 때 똑같은 옵션을 주면 호스트 볼륨에 지정된 경로로 바인딩되므로 중요한 Container와 생명주기가 다른 컨텐츠는 이런식으로 볼륨지정해서 관리하면 됩니다.

 

> docker exec -i -t my-nginx bin/bash

  • 옵션 -i 는 표준 입력(stdin)을 활성화 합니다.

  • 옵션 -t 는 TTY 모드(pseudo-TTY)를 사용합니다.

  • -i 와 -t는 Bash를 사용하려면 반드시 이 옵션을 설정해야 합니다. bash를 나가는 건 exit 하면됩니다.

  • 예를 들면

    • > apt-get update

    • > apt-get install procps   : ps 명령을 쓰기 위함

    • > ps ax

    • > apt-get install -y vim

> docker exec my-nginx echo "hello world!!"

> docker exec my-nginx ls /usr/

> docker diff my-nginx 

  • Container 실행 후 변경 사항을 확인(diff) 후 , 다시 이미지로 생성을 하는 것은 위에서 살펴본 commit 해본다.

> docker commit -a "dennis@sptek.co.kr" -m "second commit on SPtek" my-nginx ksh4602/nginx:0.2

> docker stop my-nginx

> docker run -d -p 8080:80 --name my-nginx2 my-nginx:1.0

 

(2) Dockerfile  - Dockerfile(명세) 작성 -> docker build -> docker run

https://docs.docker.com/engine/reference/builder/

Dockerfile은 Docker의 이미지 생성 파일이고, Dockerfile에 설정된 것대로 이미지가 만들어진다.

 

  • dockerOutput 디렉토리를 만들고, windows 10인 관계로 vim을 따로 설치. (  https://www.vim.org/download.php )

  • > vim Dockerfile

    • FROM nginx

    • RUN apt-get update

    • RUN apt-get install -y procps

    • RUN apt-get install -y vim

  • > docker build -t my-nginx-image .

    • 실행하면, Dockerfile의 내용에 따라, nginx를 받고, RUN에 지정된 명령을 하나씩 실행한 뒤에 이미지가 생성됨.

    • 마침표(.) 현재 위치를 나타냄으로 생략하면 안됨

    • 이미지명은 my-nginx-image 로 하고 태그를 넣지 않았으니, 자동으로 latest 

  • > docker images

  • > docker run -d p 8080:80 --name my-nginx3 my-nginx-image

  • > docker exec my-nginx3 ps ax

 

(3) Docker 빌더를 위한 jib plugin

 

 

 

5. Docker Network

 

** docker network 부분은 좀 더 업데이트가 필요함 

 

  • 컨테이너 내부 IP 를 순차적으로 할당하고 컨테이너가 재시작할 때 마다 부여된 IP가 변경될 수 있음.

  • 내부 IP는 도커가 설치된 호스트의 내부망에서만 쓸 수 있기 때문에 외부와 통신을 하기 위해서
    veth 라는 네트워크 인터페이스를 생성하여 외부와 통신한다.

  • 도커가 설치된 호스트에서 ifconfig나 ip addr 같은 네트워크 명령어로 살펴보면
    실행중인 컨테이너 수 만큼 veth*로 시작되는 인터페이스가 생성된 것을 알수 있다.

    • apt-get install net-tools 

    • ifconfig

  • eth0 :  내부IP가 외부로 통신하기 위한 인터페이스로 호스트의 네트워크이다. Eth0 네트워크가 각 veth*로 시작하는 네트워크와 통신한다.

  • docker0 : veth* 인터페이스와 바인딩되어 호스트의 eth0 인터페이스와 이어주는 역활을 한다.

  • 도커가 제공하는 기본적인 네트워크는 bridge, host, none, container, overlay가 있다.

    도커를 설치하면 기본적으로 docker0 브릿지를 통해 외부외 통신 할수 있으며 선택에 따라 여러 네트워크 드라이버를 사용 할 수도 있다.

 

  • docker network ls

    • 도커에 생성된 네트워크 확인

  • docker network create --driver bridge mybridge

    • 사용자 정의 브릿지를 새로 생성하여 각 컨테이너에 연결한다.

      컨테이너는 연결된 브릿지를 통해 외부와 통신한다.

    • docker create 또는 run 명령어에 --net 옵션의 값을 설정하면, 컨테이너가 해당 네트워크를 사용한다.

    • run 명령시 --net-alias 옵션을 쓰면 alias 이름으로 여러 개의 컨테이너에 접근이 가능하고,

      컨테이너 생성이 완료되면 ping을 사용해서 각 컨테이너로 ping이 전송되는 것을 확인 할 수 있다.

      Ping이 전달되는 IP는 라운드로빈 방식으로 도커 엔진에 내장된 DNS가 alias 호스트 이름을 설정한 컨테이너로 변환(resolve) 하기 때문이다.

  • docker run -it --name container_name --net host nginx

    • 호스트 네트워크는 호스트의 네트워크 환경을 그대로 사용한다.

      호스트 머신에서 설정한 호스트 이름을 컨테이너가 상속받기 때문에 컨테이너의 호스트 이름도 무작위 16진수가 아닌 도커 엔진이 설치된 호스트 머신의 호스트 이름이 설정된다.

  • docker run -it --name container_name --net none nginx

    • 어떠한 네트워크도 사용하지 않겠다란 뜻, 외부와의 연결이 단절된다.

  • docker run -it --name container_name --net container:container_id nginx

    • 이 네트워크는 다른 컨테이너의 네트워크 환경을 공유할 수 있다.

      공유되는 속성은 내부 IP, 네트워크 인터페이스의 MAC 주소 등이다.

 

 

 

6. Docker Compose

** Docker-Compose 부분은 좀 더 업데이트가 필요함 

 

https://docs.docker.com/compose/overview/

https://docs.docker.com/compose/compose-file/

https://docs.docker.com/compose/gettingstarted/

 

  • 한개 이상의 Docker 명세를 한번에 할수 있도록 한다.

  • 예를 들어서 신규 개발자 개발 환경 구성은 docker-compose.yml 포함된 git repo만 전달하면 끝난다.

  • Mysql, RabbitMQ, Redis 등등을 묶어서 배포하고, depend_on으로 디펜던시 정의

  • docker-compose만 잘 만들어두면 로컬 개발 속도가 빨라짐.

 

이것과 관련된 Compose command-line reference 도 많습니다요.

https://docs.docker.com/compose/reference/

 

 

> docker-compose up -d

> open http://localhost:8000

> docker-compose down

> docker-compose ps

 

7. 그 밖에 

 

- 멀티스테이지 빌드

https://docs.docker.com/develop/develop-images/multistage-build/

  • 빌드를 위한 패키지 설치시에는 Docker Image가 너무 커지는데 비해, 정작 런타임에 사용하는 artifact 용량은 적어,

    빌드와 런타임을 나누는 것을 멀티스테이지 빌드 라고 한다.

 

To be continues....