[0717] docker 실습

nikevapormax·2022년 7월 17일
0

TIL

목록 보기
75/116
post-thumbnail

docker

docker 란?

  • 리눅스의 응용 프로그램들을 프로세스 격리 기술들을 사용해 container로 실행하고 관리하는 오픈 소스 프로젝트
  • docker container는 일종의 소프트웨어를 소프트웨어의 실행에 필요한 모든 것을 포함하는 완전한 파일 시스템 안에 감싼다.
    • 코드, 런타임, 시스템 도구, 시스템 라이브러리 등 서버에 설치되는 무엇이든 포함한다.
    • 이를 통해 실행 중인 환경에 관계 없이 언제나 동일하게 실행될 것을 보증한다.

공식 튜토리얼 실습

튜토리얼 image를 생성하고 실행

  • docker에서 기본 튜토리얼로 제공해주는 getting-started 이미지를 80번 포트에 연결해 이미지를 확인해보자.
    • image가 없더라도 아래와 같이 그냥 명령어를 입력해 돌리면 image가 생성된 후 container가 실행된다.
$ docker run -d -p 80:80 docker/getting-started

>>> -d : image를 돌리면서 터미널을 사용하겠다.
>>> -p : port 연결
>>> docker/getting-started : docker hub의 docker 레지스트리에 있는 getting-started 라는 image를 사용하겠다.
                             (image 뒤에 tag를 붙이지 않으면 자동적으로 latest가 붙음)
  • iTerm에서 해당 코드를 실행해보자.
    • 만약 내가 실행하고자 하는 image가 내 로컬에 존재하지 않는다면, image를 다운받아서 실행한다. 따라서 처음 실행때 시간이 좀 걸릴 수 있다.
  • image가 잘 실행되고 있는지 확인해보자.
  • 첫 번째 방법은 docker desktop에서 확인하는 것이다.
  • 두 번째 방법은 terminal에서 아래의 명령어를 입력해 확인하는 것이다.
$ docker ps

  • 두 가지 방법을 확인해 보면, 둘 다 container의 이름이 같은 것을 확인할 수 있다. (따라서 자기에게 맞는 방식을 사용하면 될 것 같다.)
  • 이제 브라우저로 가 localhost:80을 주소창에 입력한 후 엔터를 치면 아래의 화면을 볼 수 있다.

Dockerfile 작성

  • 이제 실습을 진행하기 위해 docker에서 제공하는 application을 받아보도록 하자.
  • 파일을 다운받고 압축을 해제한 뒤, vscode로 열어보면 아래의 파일 구조를 볼 수 있다.
  • 우리가 받은 application은 node.js를 사용하고 있다.
  • 나는 이제 이 application을 사용해 image를 만들 것이다.
  • 먼저 (쉽게 생각하면) image를 만들기 위한 설명서가 필요하다. 그러므로 Dockerfile을 생성하도록 하겠다.
    • 이름은 항상 Dockerfile로 짓고, 뒤에 아무런 생성자가 붙지 않는다.
    • 만들면 docker의 상징인 고래가 아이콘으로 보이게 된다.
# 현 application은 javascript로 만들어졌다. 
# 따라서 그것을 돌리기 위한 엔진인 node를 받아오고, 그것의 버전으로 12를 사용하는데
# 경량화된 버전인 alpine을 사용한다.
FROM node:12-alpine

# 애플 m1 MacBook을 사용하기 때문에 추가해줌
RUN apk add --no-cache python2 g++ make

# 현 application을 실행할 곳은 container의 app 폴더 안 이다.
WORKDIR /app
# 현 application 안에 있는 것을 워킹 디렉토리의 /app 안으로 복사해 주겠다.
COPY . .

# 실행
# yarm instal은 pip install과 동일하다고 보면 됨
RUN yarn install --production
# node를 실행하며, src 파일 안에 있는 index.js를 실행시킨다.
CMD ["node", "src/index.js"]

image 생성 후 실행

  • 이제 terminal로 가 실행해보도록 하겠다.
  • 항상 유의해야 할 점은 내가 만든 Dockerfile이 있는 곳에서만 image가 생성된다는 것이다. 다른 곳에서 하면 무조건 안 된다.
  • image를 생성해보자.
$ docker build -t getting-started .

>>> -t : tag를 붙여줌
>>> . : 현재 파일에서 Dockerfile을 찾아라

  • 생성된 image를 확인해보자.
    • 현재는 image를 생성한 것이지 container를 실행한 것은 아니다.
    • 특정 태그값을 입력하지 않으면 latest가 자동적으로 붙는다. 실제 본인의 프로젝트를 image로 만든다면 getting-started:1.0.0과 같이 버전을 붙여주는 것이 이상적일 것이다.

  • container를 실행해보자.
$ docker run -dp 3000:3000 getting-started
$ docker ps

  • 브라우저로 가 localhost:3000을 입력하면 다음과 같은 페이지가 나오게 된다.

image와 container 업데이트

  • 지금 우리가 띄운 container의 image에는 placeholder로 New Item이 있고, 버튼에는 Add Item이 있다.
  • 이것을 한글화 패치를 하고 다시 띄워보도록 하겠다.
  • vscode로 돌아와 src/js/app.js 파일의 99 번째 줄과 109 번째 줄을 한글로 수정해보자.
  • 파일을 저장하고 브라우저로 돌아가보면 반영이 되어 있을까??
    • 됐을리가 없다! 당연히 변경 전의 파일이 image로 만들어져서 실행되고 있기 때문이다.
    • 그러면 우리가 변경된 파일을 올리려면 어떻게 해야 할까??
    • 지금 단계에서는 새로운 image를 생성해 다시 container를 돌리는 방법이 있다.
  • 다시 image를 생성하고 실행해보도록 하자.
    • 똑같은 이름의 image를 만들어주면 이전 image의 이름이 <none>으로 변경된다.
$ docker build -t getting-started .
$ docker run -dp 3000:3000 getting-started

  • 위의 결과에서 보이다싶이 이미 우리는 3000번 포트를 사용하고 있다.

    • 만약 3000번 포트를 docker image가 아닌 다른 것이 사용하고 있다면 어떻게 찾을 수 있을까?
    • 3000번을 쓰는게 docker 라면 docker ps로 바로 찾을 수 있다.
    • 하지만 다른 것이 있다면?
    • 아래의 명령어를 통해 무엇이 돌아가는지 확인할 수 있다. (mac 용)
      $ lsof -i :3000
    • 두 가지 해결방법이 있다.
      • 단순하게 이전 container를 삭제하고 container를 다시 돌린다.
      • 포트 번호를 바꿔서 돌려준다. (좋지 않다.)
  • 나는 이전 container를 삭제하고 새로 만든 container를 돌려보도록 하겠다.

    • 먼저 container를 멈춘다. (docker ps로 찾을 수 있다.)
      $ docker stop {container_id}
    • docker ps -a를 통해 멈춰있는 container들을 확인할 수 있는데, 방금 전 멈춘 container가 아직도 있는 것을 알 수 있다.
    • 따라서 해당 container를 완전히 삭제해주도록 하겠다.
      $ docker rm {container_id}
    • 난 멈추고 지우는게 너무 귀찮아 하면 아래 명령어로 한 번에 멈추고 지울 수 있다.
      $ docker rm -f {container_id}
    • 다시 container를 생성해 실행하도록 하자.
      $ docker run -dp 3000:3000 getting-started
      $ docker ps
  • 브라우저로 돌아가 적용이 잘 되었는지 확인해보도록 하겠다.

  • 작동은 잘 되지만 불편한 점이 많았다.

    • 먼저 변경되는 사항이 있으면 image를 만들어줘야 되고, container도 다시 열어주고 이전꺼는 지워야 했다.
    • 이전 container에서 작성했던 내용이 하나도 남지 않는다.

docker hub에 image 푸시

  • docker hub에 가입하고, repository를 생성해준다.
  • 화면 오른쪽에 있는 Docker Commands를 살펴보도록 하자.
    • 하단의 명령어를 통해 내 로컬에 있는 image를 docker hub으로 push할 수 있다.
$ docker push {user_id}/{image_name}:{tagname}

>>> tagname : image의 특정 버전을 쓸 수 있으며, 쓰지 않으면 latest가 된다.
  • 일단 push를 해보자.
    • 그러면 아래와 같이 에러가 날 것이다.
    • 왜냐하면 wjdeorms27/getting-started라는 이름의 image가 내 로컬에 존재하지 않기 때문이다.
  • 아래의 명령어를 통해 image의 이름을 변경해주도록 하자.
    • image들을 보면 tag를 사용하면 기존 image의 이름을 변경한 똑같은 image가 생기는 것을 볼 수 있다.
$ docker tag getting-started {user_id}/getting-started

  • 그리고 다시 push를 진행한다.
    • 만약 로그인이 되지 않았다면 거절당할 것이다. 그러면 로그인을 진행해주면 된다.
      $ docker login -u {user_id}
  • 이제 docker hub으로 가 잘 올라갔는지 확인해보도록 하겠다.

새로운 환경에서 container 실행

  • play with docker라는 곳에서 container를 실행해보도록 하겠다.
  • 홈페이지에 들어가 스크롤을 내리다보면 start 버튼이 있고, 이것을 누르면 아래 화면으로 들어가진다. 여기서 빨간 박스를 클릭해 인스턴스를 추가하면 된다.
  • 아래와 같이 실행하면 대다수 돌아가지만 맥은 바로 되지 않는다. (m1 ㅠ)
  • 따라서 이에 맞게 image를 변경해주도록 하겠다.
$ docker build --platform=linux/amd64 -t {user_id}/{image_name}:amd64 .

>>> tag는 알아보기 쉽게 amd64로 선택

  • 바로 docker hub에 push해주도록 하자.
$ docker push wjdeorms27/getting-started:amd64

  • docker hub에 가 확인해보자.
  • image가 잘 생성되고 hub에도 올라가 있으니 다시 실행하도록 하겠다.
  • 잘 실행이 되면 위와 같이 3000 번 포트가 생기게 된다. 이것을 누르면 우리가 만든 application을 확인할 수 있다.

docker image와 container 정리하기

  • container를 멈추고 삭제해도 되지만, 이번에는 한 번에 정리하는 코드를 사용해 보았다.
$ docker rm -f {container_id}

  • 또는 docker desktop에서 아래와 같이 삭제버튼을 눌러 삭제할 수도 있다.
  • 이제 image를 삭제해보도록 하겠다.
$ docker rmi {image_id}

docker volume 사용 (named volume)

  • docker image를 실행하고, 여기서 입력한 데이터를 application을 꺼도 유지될 수 있도록 하기 위해 volume을 만들어 사용해보자.
$ docker volume create {volume_name}

  • docker desktop에서 생성한 volume을 확인해보자.
  • 이제 getting-started를 실행해 container를 띄우고, 여기에 우리가 생성한 volume을 연결해서 사용해보자.
$ docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started

>>> -v : 볼륨을 연결한다.todo-db를 연결할 건데 위치는 /etc/todos이다.

  • 브라우저로 가 데이터를 저장해보자.
  • 그리고 방금 돌린 container를 종료하도록 하겠다. 그리고 다시 실행한 후 브라우저에 가 이전의 데이터가 남아있는지 확인해보도록 하겠다.

  • 만약 여기서 포트 번호를 바꾸면 어떻게 될까??
    • 데이터가 그대로다.
    • 심지어 둘 중 하나의 데이터를 수정한 후, 다른 포트로 가서 새로고침을 하면 데이터가 같이 변경되는 것을 볼 수 있을 것이다.
    • 왜냐하면 같은 volume을 공유하고 있기 때문이다.
  • 내가 만든 volume의 목록을 보고 싶다면 아래의 명령어를 활용하면 된다.
$ docker volume ls
  • 그렇다면 나의 volume은 어디에 위치하고 있을까?
    • Mountpoint에 위치하고 있다.
    • 그러나 local에서 실제로 가보려하면 들어갈 수 없다.
    • 이것은 virtual machine에서 존재하고 있기 때문에 내 로컬 피시에서는 접근할 수 없다.
$ docker volume inspect todo-db

bind mount

  • 이전까지는 파일의 사소한 변화에도 image를 다시 빌드하고 container를 다시 띄우고하는 등 많은 변화를 필요로 했었다.

  • 이러한 변경 활동을 하지 않아도 되는 방식을 소개하겠다.

  • 우리가 맨 처음 받아와 사용하던 application을 volume처럼 사용해 container에 탑재하게 된다면 파일에 수정 사항이 생기더라도 위와 같은 노동을 하지 않아도 된다.

  • 실습에 앞서 현재 돌아가고 있는 container들을 모두 꺼주자.

    • cli 든 docker desktop 이든 편한 방식으로 꺼주면 된다.
  • bind mount를 하기 위해서는 우리의 프로젝트가 있는 파일로 이동해주어야 한다.

  • bind mount의 3 가지 명령어

    • 백슬래시(\)를 사용해 다음 줄로 넘어가자!
    • 기본
      docker run -dp 3000:3000 \
       -w /app -v "$(pwd):/app" \
       node:12-alpine \
       sh -c "yarn install && yarn run dev"
    • 파워쉘
      docker run -dp 3000:3000 `
       -w /app -v "$(pwd):/app" `
       node:12-alpine `
       sh -c "yarn install && yarn run dev"
    • 애플 실리콘 (m1)
      docker run -dp 3000:3000 \
       -w /app -v "$(pwd):/app" \
       node:12-alpine \
       sh -c "apk add --no-cache python2 g++ make && yarn install && yarn run dev"
       
       >>> $(pwd) : 현재 폴더를 입력하는 것이다. 현재 Dockerfile이 있는 곳을 입력해주어야 한다. 
                    해당 명령어를 그대로 입력하면 됨.
  • 나의 경우 해당 명령어를 입력하면서 에러가 났다. 만약 맥북인데 에러가 난다면 시스템 환경설정 > 보안 및 개인 정보 보호 > 전체 디스크 접근 권한 > docker 체크하기의 순으로 권한을 부여하면 된다.

  • 위의 코드를 실행하면 다음과 같이 된다.

    • 현재 완벽하게 생성된 것은 아니다. 그래서 log를 확인해보고 싶다면 아래 명령어를 사용하면 된다.
      $ docker logs -f {container_id}
      
      >>> 실시간으로 생성되는 것을 확인할 수 있음
      >>> -f가 없으면 잠깐의 log만 나옴
  • 완벽하게 만들어졌으면 아래의 화면이 나오게 된다.

    • 아래의 Listening on port 3000이 보이게 되면 control + c를 눌러 logs에서 빠져나오면 된다.
  • 그리고 docker desktop에서 확인해보면 container가 돌아가고 있는 것을 볼 수 있다.

  • 브라우저를 확인해보자.

  • 잘 돌아가니 이제 마지막으로 영어인 부분을 한글화해보도록 하겠다.

  • 위와 같이 수정한 후 저장하고, 브라우저에 가서 새로고침을 하면 변경된 부분이 바로 적용되는 것을 확인할 수 있을 것이다.

멀티컨테이너가 필요한 이유

container 간 소통에 필요한 network 생성

  • docker는 각 container가 endpoint를 network와 연결하고 이를 통해 통신하도록 한다.
  • 따라서 소통에 필요한 network를 생성해보도록 하겠다.
$ docker network create todo-app
  • 나의 경우 이미 존재해 다음과 같이 network 리스트를 확인하고 존재하던 todo-app을 삭제한 뒤 다시 만들었다.

mysql container 띄우기

  • mysql container를 만들어서 현재 만든 network에 attach해보도록 하겠다.

    • 대다수의 경우

      $ docker run -d \                                        
      --network todo-app --network-alias mysql \
      -v todo-mysql-data:/var/lib/mysql \
      -e MYSQL_ROOT_PASSWORD=secret \
      -e MYSQL_DATABASE=todos \
      mysql:5.7
      
      >>> --network-alias : 네트워크의 이름을 설정해줄 수 있음
      >>> -v todo-mysql-data:/var/lib/mysql : 볼륨을 따로 만들지 않아도 다음과 같이 쓰면 자동으로 생성해줌
                                                그리고 저장할 위치를 작성하면 됨
      >>> MYSQL_ROOT_PASSWORD= : mysql에 접근할 때 필요한 비밀번호 설정
      >>> MYSQL_DATABASE= : 데이터베이스 이름을 설정해줌
      >>> mysql:5.7 : 사용할 mysql 버전 
    • 만약 나와 같이 m1 노트북이라면 추가로 설정할 부분이 있다.

      $ docker run -d \                                        
      --network todo-app --network-alias mysql --platform linux/amd64 \
      -v todo-mysql-data:/var/lib/mysql \
      -e MYSQL_ROOT_PASSWORD=secret \
      -e MYSQL_DATABASE=todos \
      mysql:5.7

  • docker desktop으로 가 container가 실행되는 것을 확인해보자.

  • 이제 데이터베이스를 확인하도록 하자.

$ docker exec -it {container_id}

멀티 컨테이너 연결하기

  • 현재 네트워크에서 mysql container가 돌아가고 있다. 어떻게 돌아가고 있는지 확인해보도록 하겠다.
  • 아래의 명령어를 사용한다.
$ docker run -it --network todo-app nicolaka/netshoot

>>> nicolaka/netshoot : https://github.com/nicolaka/netshoot의 이미지 사용

  • dig mysql 명령어를 입력하면 아래의 화면이 나온다.
    • 현재 mysql이 172.18.0.2 포트에 DNS처럼 연결된 것을 볼 수 있다.
    • 이는 우리가 mysql container를 띄울 때 alias를 사용해 별명을 지어주었기 때문이다.
  • 이제 nicolaka/netshoot은 사용하지 않을 것이기 때문에 삭제해준다.
  • 그리고 원래 돌고 있었던 node도 삭제해주도록 하자.
  • 우리가 방금 띄웠던 mysql을 연결해보도록 하겠다.
$ docker run -dp 3000:3000 \                             
> -w /app -v "${pwd}:/app" \
> --network todo-app \
> -e MYSQL_HOST=mysql \
>  -e MYSQL_USER=root \
> -e MYSQL_PASSWORD=secret \
> -e MYSQL_DB=todos \
> node:12-alpine \
> sh -c "yarn install && yarn run dev"

  • docker logs {container_id}를 통해 잘 연결이 되었는지 확인할 수 있다.
  • 브라우저로 가서 내용을 입력한다.
  • 다음 명령어를 통해 mysql에 저장된 내용을 확인할 수 있다.
    • 아까 설정한 비밀번호인 secret을 입력해주면 된다.
$ docker exec -it {container_id} mysql -p todos
  • 그리고 db의 내용을 확인하기 위해 아래의 쿼리를 입력해준다.
    • 한글로 넣으면 깨져서 물음표로 나오게 된다.
    • 영어는 잘 나온다.
$ select * from todo_items;
profile
https://github.com/nikevapormax

0개의 댓글