도커/쿠버네티스 컨테이너 개발 실전 입문 · · 9 min read

CH02. 도커 컨테이너 배포

1. 컨테이너로 어플리케이션 실행하기

  • 도커 이미지 : 도커 컨테이너를 구성하는 파일 시스템과 실행할 어플리케이션 설정을 하나로 합친 것으로 컨테이너를 생성하는 템플릿 역할을 한다.

  • 도커 컨테이너 : 도커 이미지를 기반으로 생성되며, 파일 시스템과 어플리케이션이 구체화되어 실행되는 상태

  • 도커 이미지와 도커 컨테이너

    • 테스트 이미지 받아오기
      $ docker image pull gihyodocker/echo:latest
      $ docker image list
      
    • 받아온 이미지를 기반으로 컨테이너 생성 및 포트포워딩
      $ docker container run -t -p 9000:8080 gihyodocker/echo:latest
      
    • 터미널을 하나 더 띄워 테스트
      $ curl http://localhost:9000/
      
    • 컨테이너 정지
      • 컨테이너의 아이디를 알아온다.
        $ docker container list
        
      • 알아온 컨테이너 아이디를 stop 시킨다.
        $ docker container stop [container id]
        
  • 간단한 애플리케이션과 도커 이미지 만들기

    • 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)
          }
      }
      
    • Dockerfile 작성
      FROM golang:1.9
      RUN mkdir /echo
      COPY main.go /echo
      CMD ["go", "run", "/echo/main.go"]
      
    • 도커 이미지 빌드
      $ docker image build -t [이미지명]:[태그명] [Dockerfile의 경로]
      $ docker image build -t test:test .
      
    • 빌드된 이미지 확인
      $ docker image list
      $ docker image ls
      
    • 빌드한 이미지로 컨테이너 생성
      $ docker container run test:test        # 일반 실행
      $ docker container run -d test:test     # 데몬으로 실행
      
    • 포트포워딩
      • 8080포트로 요청을 보내도 Connection refused로 나온다.
      • 컨테이너(가상)에서 열어준 포트를 호스트 머신에 연결을 시켜주어야 한다.
      • 컨테이너의 아이디를 알아와서 stop을 실시한다.
      • 다음 명령을 실행시킨다.(컨테이너의 포트와 호스트 머신의 포트를 연결해준다.)
        $ docker container run -p 9000:8080 test:test
        $ docker container run -d -p 9000:8080 test:test
        
  • Dockerfile 인스트럭션

    • FROM : 도커 이미지의 바탕이 될 베이스 이미지를 지정
    • RUN : 도커 이미지를 실행할 때 컨테이너 안에서 실행할 명령을 정의하는 인스트럭션
    • COPY : 도커가 동작중인 호스트 머신의 파일이나 디렉터리를 도커 컨테이너 안으로 복사하는 인스트럭션
    • CMD : 도커 컨테이너를 실행할 때 컨테이너 안에서 실행할 프로세스를 지정한다.
      • RUN 인스트럭션은 이미지를 빌드할때 실행되고 CMD 인스트럭션은 컨테이너를 시작할 때 한 번 실행된다.
    • ENTRYPOINT : 컨테이너의 명령 실행 방식을 조정할 수 있으며, CMD와 마찬가지로 컨테이너 안에서 실행할 프로세스를 지정하는 인스트럭션이다.
      • ENTRYPOINT를 지정하면 CMD의 인자가 ENTRYPOINT에서 실행하는 파일에 인자로 주어진다.
    • LABEL : 이미지를 만든 사람의 이름 등을 적을 수 있다. 전에는 MAINTAINER라는 인스트럭션도 있었으나 더 이상 사용하지 않는다.
    • ENV : 도커 컨테이너 안에서 사용할 수 있는 환경변수를 지정한다.
    • ARG : 이미지를 빌드할 때 정보를 함께 넣기 위해 사용한다. 이미지를 빌드할 때만 사용할 수 있는 일시적인 환경변수이다.

2. 도커 이미지 다루기

  • docker image 에서 사용할 수 있는 명령어 list

    $ docker image --help
    build       # 이미지 빌드
    history     # history를 보여준다
    inspect     # 임포트
    load        # 로드한다.
    ls          # 이미지 리스트를 보여준다.
    prune       # 사용하지 않는 이미지를 제거
    pull        # 저장소에서 이미지를 받아온다.
    push        # 저장소에 이미지를 올린다.
    rm          # 제거한다.
    save        # tar로 이미지를 저장한다.
    tag         # 태그를 생성한다.
    
  • docker image build : 이미지 빌드

    • docker image build -t 이미지명[:태그명] Dockerfile경로 : -t 옵션을 사용하여 태그명을 사용할 수 있다.
    • docker image build -f Dockerfile-test -t 이미지명[:태그명] Dockerfile경로 : 기본으로 Dockerfile을 찾으나 -f옵션을 사용하여 다른이름의 Dockerfile을 사용할 수 있다.
    • docker image build --pull=true 이미지명[:태그명] Dockerfile경로 : –pull옵션을 사용하면 매번 베이스 이미지를 강제로 새로 받아온다.
  • docker search : 이미지 검색

    • docker search [option] 검색키워드
    • docker search --limit 5 mysql
    • 리포지토리는 검색할 수 있지만 태그까지는 검색할 수 없다.
    • 리포지토리에 공개된 이미지의 태그를 알고 싶다면 도커 허브의 해당 리포지토리 페이지에서 Tags를 보는 방법이나 API를 사용하는 방법 중 하나를 사용하면 된다.
      • API : curl -s 'https://hub.docker.com/v2/repositories/library/golang/tags/?page_size=10' | jq -r '.results[].name'
  • docker image pull : 이미지 내려받기

    • docker image pull [options] 리포지토리명[:태그명]
  • docker image ls : 보유한 도커 이미지 목록 보기

    • docker image [options] ls
  • docker image tag : 이미지에 태그 붙이기

    • 도커 이미지의 버전을 구별하기 위한 것이다.
      • IMAGE ID는 도커 이미지의 버전 넘버 역할을 한다. 어플리케이션을 수정하고 이미지를 빌드하면 매번 다른 이미지가 된다.
      • Dockerfile을 편집했을 때뿐만 아니라 COPY 대상이 되는 파일의 내용이 바뀌어도 IMAGE ID 값이 바뀐다.
    • 이미지 ID에 태그 부여하기
      • 도커 이미지에 태그를 지정하지 않고 빌드한 이미지는 기본적으로 latest 태그가 부여된다.
      • docker image tage 기반이미지명[:태그] 새이미지명[:태그]
  • docker image push : 이미지 외부에 공개하기

    • docker image push [options] 리포지토리명[:태그] : 지정된 리포지토리에 업로드된다.

3. 도커 컨테이너 다루기

  • 도커 컨테이너의 생애주기

    • 실행 중 상태
      • docker container run 명령으로 이미지를 기반으로 컨테이너를 생성한 상태
    • 정지 상태
      • 실행 중 상태에 있는 컨테이너를 사용자가 명시적으로 정지하거나 컨테이너에서 실행된 어플리케이션이 정상/오류 여부를 막론하고 종료된 경우
      • 디스크에 컨테이너가 종료되던 시점의 상태가 저장되어 남는다.
      • 정지시킨 컨테이너를 다시 실행시킬 수 있다.
    • 파기 상태
      • 정지 상태의 컨테이너는 명시적으로 파기하지 않는 이상 디스크에 그대로 남아 있다.
      • 디스크를 차지하는 용량이 점점 늘어나므로 불필요한 컨테이너를 완전히 삭제하는 것이 바람직하다.
      • 한 번 파기한 컨테이너는 다시 실행할 수 없다는 점에 유의해야한다.
  • docker container run : 컨테이너 생성 및 실행

    • docker container run [options] 이미지명[:태그] [명령] [명령인자...]
    • docker container run [options] 이미지ID [명령] [명령인자...]
    • -d 옵션 : 백그라운드에서 실행
    • -p 옵션 : 포트포워딩
    • -it 옵션 : /bin/sh로 쉘을 실행할 수 있다.
    • 컨테이너에 이름 붙이기
      $ docker container run --name [컨테이너명] 이미지명[:태그]
      
    • 도커 명령에서 자주 사용되는 옵션
      • -i 옵션 : 컨테이너를 실행할 때 컨테이너 쪽 표준 입력과의 연결을 그대로 유지한다.
      • -t 옵션 : 유사 터미널 기능을 활성화하는 옵션. -i 옵션과 함께 -it로 쓴다.
      • –rm 옵션 : 컨테이너를 종료할 때 컨테이너를 파기하도록 하는 옵션
      • -v 옵션 : 호스트와 컨테이너 간에 디렉터리나 파일을 공유하기 위해 사용하는 옵션
  • docker container ls : 도커 컨테이너 목록 보기

    • docker conatiner ls [options]
    • 조회시 각 항목의 의미
      • CONTAINER ID : 컨테이너 식별자
      • IMAGE : 컨테이너를 만드는데 사용된 도커 이미지
      • COMMAND : 컨테이너에서 실행되는 어플리케이션 프로세스
      • CREATED : 컨테이너 생성 후 경과된 시간
      • STATUS : Up(실행중), Exited(종료) 등 컨테이너의 실행 상태
      • PORTS : 호스트 포트와 컨테이너 포트의 연결 관계(포트포워딩)
      • NAME : 컨테이너의 이름
    • 컨테이너 ID만 추출하기
      • docker container ls -q
    • 컨테이너 목록 필터링하기
      • docker container ls --filter "필터명=값"
    • 종료된 컨테이너 목록 보기
      • docker container ls -a
  • docker container stop : 컨테이너 정지하기

    • docker container stop [컨테이너ID 또는 컨테이너명]
  • docker container restart : 컨테이너 재시작

    • docker container restart [컨테이너ID 또는 컨테이너명]
  • docker container rm : 컨테이너 파기

    • docker container rm [컨테이너ID 또는 컨테이너명]
    • docker container run –rm를 사용하여 컨테이너를 정지할 때 함께 삭제할 수 있다.
  • docker container logs : 표준 출력 연결하기

    • 현재 실행 중인 특정 도커 컨테이너의 표준 출력 내용을 확인할 수 있다.
    • docker container logs [options] [컨테이너ID 또는 컨테이너명]
    • -f 옵션 : 새로 출력되는 표준 출력 내용을 계속 보여준다.
  • docker container exec : 실행 중인 컨테이너에서 명령 실행하기

    • docker container exec [options] [컨테이너ID 또는 컨테이너명] [컨테이너에서 실행할 명령]
  • docker container cp : 파일 복사하기

    • 컨테이너 끼리 혹은 컨테이너와 호스트 간에 파일을 복사하기 위한 명령
    • COPY 인스트럭션은 이미지를 빌드할 때, cp 명령은 실행 중인 컨테이너와 파일을 주고 받을 때
    • docker container cp [options] [컨테이너ID 또는 컨테이너명]:[원보파일] [대상파일]
    • docker container cp [options] [호스트_원본파일] [컨테이너ID 또는 컨테이너명]:[대상파일]

4. 운영과 관리를 위한 명령

  • prune : 컨테이너 및 이미지 파기

    • docker container prune [options]
      • 실행중이 아닌 모든 컨테이너를 삭제하는 명령
    • docker image prune [options]
      • 태그가 붙지 않은 모든 이미지를 삭제한다.
    • docker system prune
      • 사용하지 않는 도커 이미지 및 컨테이너, 볼륨 네트워크 등 모든 도커 리소스를 일괄적으로 삭제
  • docker conatiner stats : 사용 현황 확인하기

    • 시스템 리소스 사용 현황을 컨테이너 단위로 확인
    • docker container stats [options] [대상_컨테이너ID ...]

5. 도커 컴포즈로 여러 컨테이너 실행하기

  • 도커는 어플리케이션 배포에 특화된 컨테이너이다.

    • 도커 컨테이너 = 단일 어플리케이션
    • 어플리케이션 간의 연동 없이는 실용적 수준의 시스템을 구축할 수 없다. 다시말해, 도커 컨테이너로 시스템을 구축하면 하나 이상의 컨테이너가 서로 통신하면, 그 사이에 의존관계가 생긴다.
    • 컨테이너 동작을 제어하기 위한 설정 파일이나 환경 변수를 어떻게 전달할지, 컨테이너 의존관계를 고려할 때 포트 포워딩을 어떻게 설정해야 하는지 등의 요소를 적절히 관리해야 한다.
  • docker-compose 명령으로 컨테이너 실행하기

    • compose는 yaml 포멧으로 기술된 설정 파일로, 여러 컨테이너의 실행을 한 번에 관리할 수 있게 해준다.
    • docker-compose version
      • ubunut : sudo yum install -y docker-compose
      • centos7 : sudo apt install -y docker-compose
    • docker-compose.yml 작성
      • docker container run -d -p 9000:8080 example/echo:latest
      • docker-compose.yml
        version: "3"
        servicese:
            echo:
                image: example/echo:latest
                ports:
                    -   9000:8080
        
      • docker-compose up -d
    • 실행 확인
      • docker container ls
    • 컨테이너 정지
      • docker-compose down
  • image 속성 대신 build 속성 사용

    version: "3"
    servicese:
        echo:
            build: .
            ports:
                -   9000:8080
    
  • –build 옵션

    • docker-compose up 명령에서도 도커 이미지를 강제로 다시 빌드하게 할 수 있다. 개발 과정에서 이미지가 자주 수정되는 경우에 사용하는 것이 좋다.

6. 컴포즈로 여러 컨테이너 실행하기

  • 젠킨스 master-slave 노드 구성
  • docker-compose.yml
    version: "3"
    services:
        master:
            container_name: master
            image: jenkinsci/jenkins:latest
            ports:
                -   8080:8080
                -   50000:50000
            volumes:
                -   ./jenkins_home:/var/jenkins_home
            links:
                -   slave01
    
        slave01:
            container_name: slave01
            image: jenkinsci/ssh-slave:latest
    
  • 도커 컴포즈 실행
    $ docker-compose up -d
    $ docker container ls
    
  • 젠킨스 시작
    • http://localhost:8080/ 으로 접속하여 로그인 후 플러그인 설치 및 사용자 생성
    • 초기 admin 비밀번호 확인
      $ cat jenkins_home/secrets/initialAdminPassword
      
    • 초기 설정이 완료되면 젠킨스관리>플러그인관리 에서 Node and Label parameter plugin을 설치한다.
  • master 노드에서 ssh 키 생성 및 확인
    $ docker container exec -it master ssh-keygen -t rsa -C ""
    $ ls -al jenkins_home/.ssh/id_ras           # 프라이빗 키
    $ ls -al jenkins_home/.ssh/id_ras.pub       # 퍼블릭 키
    
  • docker-compose.yml 수정 및 재시작
    version: "3"
    services:
        master:
            container_name: master
            image: jenkinsci/jenkins:latest
            ports:
                -   8080:8080
                -   50000:50000
            volumes:
                -   ./jenkins_home:/var/jenkins_home
            links:
                -   slave01
    
        slave01:
            container_name: slave01
            image: jenkinsci/ssh-slave:latest
            environment:
                -   JENKINS_SLAVE_SSH_PUBKEY=ssh-ras AAAA... # 퍼블릭키를 입력해준다.
    
    $ docker-compose up -d
    
  • slave 노드 추가
    • 젠킨스관리>노드관리>신규노드로 들어간다.
    • 노드명을 slave01로 하고 Permanent Agent를 선택한후 OK를 누른다.
    • Name은 slave01로 하고 Remote root directory를 /home/jenkins로 한다.
    • Launch method는 Launch agents via ssh로 설정한다.
    • HOST를 slave01로 하고 credentials 생성으로 넘어간다.
    • Credential 생성
      • Kind : SSH Username with private key
      • Username : jenkins
      • ID : jenkins
      • Private Key : Enter directly를 체크하고 프라이빗 키를 넣어준다.
      • 이후 세이브를 진행한다.
    • Credential을 방금 만든 것으로 선택하고 세이브 한다.
  • Java 위치 잡아주기
    • slave01로 접속하여 java의 위치를 잡아준다.
    $ docker container exec -it slave /bin/bash
    $ cp -rf /usr/local/openjdk-8 /usr/local/java
    
  • 대쉬보드에서 master-slave 노드의 상태를 확인한다.