INFRA - 도커 잘 쓰기 (docker how-to)

What is Docker?

Container provides isolated workspace!

나는 공용 서버에서 tensorflow를 사용하고 싶다. 불가피하게도 내가 사용해야하는 tensorflow의 버전은 1인데 현재 공용 서버에는 tensorflow 버전 2가 깔려있다. 이 때 나만의 독립적인 서버 공간을 확보해 라이브러리 사이의 충돌을 방지하는 방법은 가상 환경을 구축하거나 컨테이너를 사용하는 것이다.

전자인 가상 환경을 구축하려면 리소스가 많이 필요하다. 가상 환경마다 운영 체제가 독립적으로 생성되고 운영되기 때문이다.

하지만 후자인 컨테이너는 여러 컨테이너가 운영 체제 1개를 공유하기 때문에 하드웨어 자원(메모리)을 많이 사용하지 않는다는 장점이 있다.

컨테이너의 장점은 자원의 효율성 측면 외에도 용량이 가볍고, 유지 및 업데이트가 간편하다는 장점도 있다.

도커는 컨테이너로 호스트와 독립적인 환경을 구축한다. 도커 컨테이너에서 tensorflow 1버전을 깔아도 호스트의 tensorflow 버전에 아무런 영향을 미치지 않는다.

Image make it easy and efficient to package & run your application!

내가 기가막힌 어플리케이션을 개발했다. 친구한테 한 번 써보라고 하고 싶은데 친구가 나의 어플리케이션을 설치하고 사용하기 위해서는 무수히 많은 프로그램을 설치해야만 한다. “먼저 이 프로그램 깔고, 저 프로그램 깔고, 파이썬 버전은 3으로 업데이트 해야 돼!!!” 이렇게 아날로그식 배포 방식을 스마트하게 바꾼 것이 도커 이미지이다.

내가 어플리케이션을 개발했다면 DockerFile에 환경 구축을 위한 코드를 입력한 후 온라인 저장소에 업로드 하면 된다. 그럼 내 친구가 저장소에 배포한 나의 이미지를 다운받아 자신의 로컬 컴퓨터에서 이미지로 콘테이너를 만들면, 이제 어플리케이션을 사용할 수 있는 환경이 설정된다.

Docker Architecture

  • daemon
    • 도커 container와 REST API 통신함.
  • server
  • client

Docker Image

  • Image Layers
    • 도커 이미지는 레이어로 구성됐다. 각 레이어에는 환경 구축을 위한 코드가 들어있다. 레이어의 순서가 중요한데, 그 이유는 예를 들면 파이썬이 깔려있어야 파이썬 라이브러리를 설치할 수 있기 때문이다. 도커 이미지 유지 및 보수를 위해서는 자주 변하거나 업데이트 되야하는 레이어를 가장 위(top)에 배치해야 한다. 그 이유는 이미지 레이어가 Stack 자료 구조처럼 쌓여 있고 한 레이어가 변경되면 해당 레이어보다 상위에 있는 모든 레이어(해당 레이어의 영향을 받는 모든 상위 레이어)를 재실행하기 때문이다. 가장 상위의 레이어를 변경해야 재실행해야하는 레이어 수가 최소화된다.
  • How to create Docker image
    1. interative method: 기존 도커 이미지 환경에서 작업을 추가해 새 이미지를 만드는 방법.
    2. dockerfile method: 텍스트 파일(Dockefile)로, 도커 이미지 환경 구축을 위한 명령어가 순서대로 적혀있다. 도커 파일 명령어는 여기를 참고하자.

Docker command

Docker 정보 및 자원 사용량 확인

  • docker version
    • 도커 서버와 클라이언트의 버전 및 추가 정보를 볼 수 있다.
  • docker events
    • 도커 데몬이 요청을 받고 응답한 결과를 로그로 확인할 수 있다.
  • docker stats
    • 실행중인 컨테이너의 자원 사용량을 스트림으로 출력한다.
    • --no-stream : 스트림으로 출력하지 않는다. 명령어를 입력한 순간의 값을 출력한다.

Docker 콘테이너

  • docker ps
    • 현재 실행중인 콘테이너 리스트를 출력
    • --all : 중료 및 중지된 콘테이너까지도 출력
  • docker run

  • nvidia-docker run

Docker 파일 이동 및 복사

  • docker cp
    • 로컬 -> 도커 콘테이너
      • docker cp [local path] [container_name:path]
    • 도커 콘테이너 -> 로컬
      • docker cp [container_name:path] [local path]
# docker cp [local path] [container_name:path]
docker cp test.py tensorflow_docker:/home/sjshin/tensorflow
# docker cp [container_name:path] [local path]
docker cp tensorflow_docker:/home/sjshin/tensorflow  /home/sjshin/test.py

Docker Additional Command

도커 기본 명령어에 익숙해졌다면, 레벨업할 시간!
도커 콘테이너를 Visual Studio Code로 실행하는 방법, 서버 부팅시 콘테이너 실행 자동화, 그리고 도커 플러그인을 배워봅시다.

Visual Studio Code에서 도커 콘테이너 사용하기

  • 참고 사항
    • Local : MacOS (Visual Studio Code)
      • 필수 사항
        • docker (로컬에 도커가 설치되지 않았다면 에러가 발생함!)
        • visual studio code
    • Remote : Linux (Docker)
  • 리모트의 도커 컨테이너를 visual studio code로 실행하거나 또는 실행 중인 컨테이너를 attach하는 방법을 소개한다.

그동안 VSCode의 remote-ssh 플러그인을 사용해 서버에 접속했다. 리모트의 콘테이너 역시 같은 방법으로 접속할 수 있다. 다만 2가지 전제 조건이 있다.

  1. [Local] VSCode에서 remote-developmentremote-container 플러그인을 설치
  2. [Local] VSCode의 setting.json{"docker.host" : "ssh://ip_address"를 추가

사실 전제 조건이 3개다. 왜냐하면 2번을 수행하기 위해서는 remote-ssh 접속을 key로 하도록 설정해야 하기 때문이다.

remote-ssh 플러그인으로 리모트에 연결하는 방법은 2가지다.
하나는 접속할 때마다 ssh id@ip_address를 입력하고 비밀번호를 치는 방법이다.
또 다른 하나는 로컬의 vscode의 config 파일에 “host name”, “user”, “identityfile”(= 나의 public key 위치)를 입력하는 방법이다. 이 방법은 원격 서버에 접속할 때 매번 비밀번호를 치지 않아도 된다는 장점이 있다. 자세한 설정 방법은 여기를 참고하자. VSCode에서 도커 컨테이너를 실행하려면 반드시 2번째 방법(key 사용해 ssh 접속)으로 원격에 접속해야 한다.

앞서 말한 2번을 하는 방법은 여기에 잘 나와있다. 참고하자!

  • 주의
    • 나의 로컬 컴퓨터에 docker가 깔려 있지 않아 “docker returned an error. make sure the docker daemon is running” 에러가 났었다. 리모트에 docker가 깔려 있더라도 VSCode를 실행하는 것은 로컬이기 때문에 로컬에도 docker가 깔려 있어야 한다.

부팅시 도커 콘테이너 자동 실행

서버가 재부팅될 때 자동으로 도커 콘테이너가 생성되도록 설정해 컨테이너 실행을 자동화할 수 있다. …

도커 콘테이너 healthcheck

docker ps는 콘테이너의 상태 정보를 정확하게 출력하지 못할 수 있다. 왜냐햐면 도커 명령어가 실행된 프로세스(PID)의 상태 정보를 가져오기 때문에 프로세스는 중지되지 않았지만 도커 프로그램에 충돌이 일어난 상황에서 도커 프로그램의 오류를 잡아내지 못하기 때문이다. 콘테이너가 정상 작동 하고 있는지 알고 싶을 때 health check를 사용한다.

Reference

Docker Official Document Docker Explained
Docker Healthcheck
Docker Auto start
Systemd Explained