Docker

newhyork·2022년 8월 8일
0

Docker


  • 간단히, App을 container 기반으로 패키징 할 수 있는 가상화 도구이다.
    (VM과 container의 차이에 대해서 간단히 살펴보자.)
    • VM: 하나의 물리적 컴퓨터(host OS) 상에서, 여러 VM이 각자의 OS(guest)를 가질 수 있다.
      • 각 OS는 해당 컴퓨터의 물리적 리소스를 분할해서 사용한다.
    • container: 하나의 물리적 컴퓨터 상에서, 여러 container는 각자의 OS를 갖지 않는다.
      • 각 container는 해당 컴퓨터의 물리적 리소스를 함께 사용한다.
      • 따라서 docker의 경우, host OS상에 engine이 존재하는 형태로,
        container마다 독립적인 실행 환경을 갖게 되는 것일 뿐이다.
  • App에 대한 실행 환경을 특정함으로써,
    다른 machine에서도 항상 동일한 환경으로 App을 실행할 수 있게 해준다.
    • 팀원 각자 개발함에 있어서 local PC에서 App을 실행할 때,
      통일된 환경(버전 등)을 이용할 수 있다는 점에서 용이하다.
  • docker container OS로는 기본적으로 Linux 기반 OS을 지원한다.
    따라서, host OS도 Linux 기반 OS여야 한다.
    (container는 host OS의 kernel을 공유하는 것이기 때문이다.)
    • 하지만 Docker Desktop이, Windows에서도 linux container를 사용할 수 있게 해준다.
      (container를 만들 때, LinuxKit(linux VM)을 이용한다고 한다.)
      이에 따라, WSL2 혹은 Hyper-V를 이용한 별도의 가상화를 이용한다.
      • WSL2는 Linux kernel을 내장시킨 것으로, Linux 명령어들을 사용할 수 있게 해준다.
        - (기존에 git bash를 이용하고 있었다면, 터미널에 'wsl'를 입력함으로써
        완전한 Linux 명령어를 이용할 수 있게 된다.)
        - (Docker Desktop을 통하지 않고, docker를 직접 설치하여 사용할 수도 있지만
        Docker Desktop을 이용하여 docker를 설치하면,
        해당 machine에서 terminal에 관계없이(WSL2던 아니던),
        같은 환경을 유지하면서 docker를 사용할 수 있다는 등의 편리한 점이 있다.)

        - (WSL2도 Hyper-V를 기반으로 가상화한 것이라고 한다.)
    • (예전엔 Docker Toolbox로써,
      VMware, VirtualBox와 같은 VM을 이용하여 docker를 사용하기도 했다고 한다.
      (헷갈릴 수 있어서 덧붙이자면, 여기서 VM을 이용한다는 것은
      docker가 VM과 대비되는 container 기반이라는 개념과는 다른 얘기이다.
      단지, host OS가 Windows 등일 때, Linux인 VM에서 docker를 사용한다는 말이다.)
      하지만, 이 방법으로 docker를 사용하는 것은 더 이상 불가능하다.)
    • (Windows container도 사용 가능하지만, 잘 쓰이지 않는다.)
  • AWS EC2 서버 등에서 docker를 이용하기 위해서는,
    Install Docker Engine on Ubuntu’ 를 검색한 결과를 따라한다.

concepts


dockerfile

  • docker container를 만들기 위한 첫걸음이다.
    • 하나의 설계도로써, docker image를 build할 수 있다.
  • 하나의 App으로써 실행될 때 필요한 것들을 세팅한다.
    • 프로그래밍 언어로 작성된 소스 코드 파일
    • 각종 dependency 설치: framework, library
    • config: env variables
    • system tool: ubuntu, git
    • setup script: App 실행 관련 명령어
  • DB server와 web server 등은 App과 격리하여, 다른 container에서 실행하곤 한다.
    • container가 아닌 host OS 상에서 실행할 목적으로,
      따로 image를 만들지 않고 사용하기도 한다.
  • docker-compose를 통해, 작성된 여러 dockerfile들로 각 image를 만들고,
    여러 container로써 함께 연결해서 동작하도록 할 수 있다.
    • 주로, 하나의 서비스를 위해 필요한 App, DB, web server 등을 함께 실행하고자 사용한다.
    • 기존에 각 dockerfile 마다 직접 image를 build하고 container를 run했던 것에 비해,
      docker-compose up으로 간편하게 build 및 run 할 수 있다.
    • 확장자는 .yaml이다.

docker image

  • 앞서 dockerfile에서 세팅된 것을 토대로 실행되는 App의 snapshot으로 볼 수 있다.
  • 최초 만들어진 후, 이를 수정할 수는 없다.
  • docker container를 만들 수 있다.

docker container

  • 독립된 환경(개별적인 filesystem)에서, 앞서 생성된 docker image를 실행할 수 있는 것을 말한다.
    • 즉, container 안에서 App이 동작한다.
  • docker container들은 서로 간에 모두 분리되어 있고, 독립적이다.
    • 이로 인해, 하나의 서버에 여러 container를 띄울 수 있다.
  • docker swarm이나 k8s와 같은 orchestration을 함께 사용하여
    cluster나 pod 단위로 container(s)를 효율적으로 관리할 수 있다.
  • container 안에서 동작하는 App은, 수정이 가능하다.

usage


  • 전체적인 흐름은 다음과 같다.
  1. local PC와 App을 실행할 다른 machine(linux 서버 or PC)에 docker를 설치한다.
  2. local에서 dockerfile을 작성하고, image를 build한다.
  3. 해당 image를 Container Registry에 push한다.
  4. 해당 image를 다른 machine에서 pull한다.
  5. 해당 machine에서는, image를 토대로 container를 생성하여 App을 실행한다.
  • Container Registry은 Cloud로써, public(Docker Hub, etc.) 또는 private(AWS, etc.)을 사용한다.
  • (docker 실습을 위해 간단한 App을 준비하자.)
# docker_practice/app/app.py
from flask import Flask


def create_app():
    app = Flask(__name__)
    return app

app = create_app()


@app.route('/')
def get_home_page():
    return 'hello world!'


if __name__ == "__main__":
    app.run(host='0.0.0.0')
- docker container를 통해 배포된 서버에 접속할 수 있게 하기 위해서는
  host를 '0.0.0.0'으로 두어, 외부에 open 되도록 한다. 

install docker

  • OS에 맞게 Docker Desktop 설치.
  • Windows의 경우 WSL2와 관련하여 Linux kernel 설치에 대한 팝업이 뜬다면,
    안내에 따라 절차를 밟으면 된다.
  • docker --version: Docker 설치 완료를 확인한다.

make dockerfile

  • 앞서 WSL2를 설치한 것과 별개로, dockerfile 작성은 local에서 진행한다.
  • dockerfile에 작성된 각 line은 layer system으로 구성된다고 한다.
    • 빈번하게 변경될 수 있는 line일수록 아래에 작성하는 것이 좋다고 한다.
    • 아래에 작성될수록 바깥 layer에 존재하며, 변경된 layer의 하위 것들은 cache를 사용한다.
  • 따로 확장자는 없다.
  • ENV {env_variable_name} {value}로, 환경 변수 등을 설정할 수도 있다.
# docker_practice/app/dockerfile
FROM python:3.8-slim
- baseImage로 python이 기본적으로 설치된 것을 사용한다.


RUN pip3 install flask
- image 생성 과정에서 실행되는 명령어이다.
  - shell 명령어도 가능하므로, pip install -r requirements.txt 형태로 주로 사용한다.


COPY . /app
- RUN과 같이, image 생성 과정에서 실행되는 명령어이다. 
- 현재 dockerfile이 위치한 디렉터리(docker_practice/app)에 있는 것들을,
  container 구동 전에 image 내부의 /app 디렉터리로 미리 복사해 놓는다는 의미이다.


WORKDIR /app
- image를 통해 container를 구동할 때, 아래의 명령어들을 실행할 디렉터리를 지정한다.


CMD ["python3", "app.py"]
- container가 구동된 후 실행할 명령어이다. 
- 큰 따옴표로 감싸줘야한다. 

build docker image

  • docker images: build된 image를 확인할 수 있다.
  • docker rmi <image_id>: image를 삭제한다.
    • 단, 종료된 container 중에서도 해당 image를 사용하는 경우 삭제할 수 없다.
      따라서, 해당 container를 종료 후 삭제하고 image를 삭제할 수 있다.
    • id가 동일한 경우, image 이름(REPOSITORY)로 특정하여 제거할 수 있다.
  • docker tag {REPOSITORY_name}:{TAG_name} {~}:{~} : 생성한 image의 이름과 tag를 변경한다.
    • local에서 만든 image를 remote repository로 push하기 위해서 알맞게 작성해야 한다.
      • 변경할 REPOSITORY_name은, {user_name}/{repo_name}으로 맞춰줘야 한다.
    • 한 번 만든 image는 수정이 불가능하므로, 실제로는 새로운 이름으로 복사하는 것이다.
# local bash shell (~/docker_practice/app)
$ docker build -t flask-app . 
- -t로, flask-app이라는 이름으로 image를 만든다. 
- 맨 마지막 '.'은 build context로, 
  현재 디렉터리에 있는 dockerfile을 기준으로 image를 만든다는 의미이다.
- 이러면, local에 image를 build한 것이다. 

run docker container in local

  • docker ps: container를 확인할 수 있다.
    • -a: 종료된 것까지
  • docker logs <container_id>: 실행 중인 container의 log를 확인할 수 있다.
  • docker kill <container_id>: 실행 중인 container를 종료한다.
  • docker rm <container_id>: container를 삭제한다.
  • Docker Desktop 앱을 통해, GUI로 쉽게 container 관리를 할 수도 있다.
    • 각 container의 terminal을 열 수도 있다.
# local bash shell
$ docker run -d -p 5001:5000 flask-app
- build된 image로, container를 실행한다.
  - -d로, container를 background에서 실행한다. 
  - -p로, port를 지정해준다.
    - Flask 서버는 기본적으로 5000번 포트에서 실행된다. 
    - local machine(host)의 port인 5001번과 container port 5000번을 mapping한다.
      - container에서 실행되는 Flask의 log를 보면, IP 주소가 172.X.X.X 형태이다.
    - local machine에 5001번으로 들어오는 요청을, 
      5000번 포트인 container, 즉 Flask 서버가 실행되고 있는 곳으로 보낸다는 의미이다.
  - 해당 웹 페이지는 localhost:5001으로 접근 가능하다.  

push docker image into Docker Hub

  • (Docker Hub에 sign up한다.)
  • Create repository (repository name: docker-practice)
# local bash shell
$ docker login 
- push를 하기 위해선, login이 선행되어야 한다.
- Docker Hub repository에 해당 docker image를 저장할 계정 정보를 입력한다.


$ docker push {user_name}/{repo_name}:{tagname}
- 해당 docker image를, 로그인한 계정의 해당 repo_name으로 push한다. 
  - push할 image의 이름(REPOSITORY)은, {user_name}/{repo_name}이어야 한다.

pull docker image & run docker container with WSL2

  • install docker와 함께 WSL2을 설치했다면, Linux에 docker가 설치되어 있을 것이다.
  • (host가 동일하기 때문에 WSL2도 terminal이 local인데
    좀 더 바람직한 실습은, AWS EC2 등 다른 host에서 pull하는 것이다.)
# WSL bash shell
$ docker login


$ docker pull {user_name}/{repo_name}:{tag_name}


$ docker run -d -p 5001:5000 {user_name}/{repo_name}

0개의 댓글