Docker 조금 써보기! (a.k.a 명령어 공부)

김민우·2022년 9월 30일
0

docker

목록 보기
2/5

도커를 직접 다뤄보기 전에, 다시 한번 도커에 대해서 복기해보자!

우선 도커의 동작 순서는 다음과 같다.
1. 도커 클라이언트에 명령어를 입력 후 도커 서버로 보낸다.
2. 도커 서버에서 컨테이너를 위한 이미지가 이미 캐시되어 있는지 확인한다. (캐시되어 있다면 이미지로 컨테이너를 생성한다.)
3. 없다면 도커 허브에서 이미지를 받아온다.

이미지로 컨테이너를 생성하는 순서는 다음과 같다.
1. 먼저 파일 스냅샷이 되어있는 것을 컨테이너의 하드 디스크 부분에 올린다.
2. 시작 커맨드를 이용하여 어플리케이션을 실행한다.

이미지 내부 파일 시스템 구조를 살펴보자

docker run 이미지 이름 ls 명령어를 입력하면 된다.

  • docker : 도커 클라이언트를 언급
  • run : 컨테이너 생성 및 실행
  • 이미지 이름: 이 컨테이너를 위한 이미지
  • ls : 이 자리는 원래 이미지가 가지고 있는 시작 명령어를 무시하고 여기에 있는 커맨드를 실행하게 함
    - ls 커맨드는 현재 디렉토리의 파일 리스트를 표출한다.

예를 들어, docker run alpine ls 커맨드를 입력하면 다음과 같은 결과를 얻는다.

설명을 하자면 다음과 같다.
1. Alpine 이미지를 이용해서 컨테이너를 생성한다.
2. 생성할 때 Alpine 이미지 안에 들어있던 파일 스냅샷들 (bin dev, etc 등)이 컨테이너 안에 있는 하드 디스크로 다운로드 된다.
3. 이미지 이름 뒤에 다른 명령어를 더 붙여서 원래 이미지 안에 들어있는 기본 커맨드는 무시가 되고 ls 명령어가 실행된다.

출력 내용을 보면 bin, dev, etc 등 많은 폴더와 파일 이름들을 볼 수 있다.

어떻게 Alpine 이미지를 이용해서 ls 명령어를 실행할까?

Alpine 이미지 파일 스냅샷 안에 이미 ls를 사용 가능하게 하는 파일이 있다.

hello-world 이미지로는 ls 명령어 사용이 불가능하다.
docker run hello-world ls명령어 입력 시 다음과 같다.

내용을 보자면 excutable file not found. 라고 실행할 수 있는 파일을 못찾았다고 뜬다.

이제 컨테이너들을 나열해보자 (다양한 명령어)

현재 실행중인 컨테이너를 나열하는 명령어는 docker ps이다.

  • docker : 도커 클라이언트 언급
  • ps : process status

이해를 돕기 위해 다음을 따라해보자.
1. 2개의 Terminal을 작동시킨다.
2. 첫 번째 Terminal에서 container 하나를 실행한다.
docker run alpine ping localhost 명령어를 입력하여 로컬호스트에 핑을 지속적으로 날린다.

3. 두 번째 Terminal에서 docker ps로 확인한다.

위, 아래는 docker run alpine ping localhost 명령어를 입력하기 전, 후이다.

이미지 설명을 잠깐 해보자면,

  1. CONTAINER ID : 컨테이너의 고유한 아이디 해쉬값이다. 실제로는 더욱 길지만 일부분만 표현한다.
  2. IMAGE : 컨테이너 생성시 사용한 도커 이미지이다.
  3. COMMAND : 컨테이너 시작시 실행될 명령어이다. 대부분 이미지에 내장되어 있으므로 별도 설정이 필요없다.
  4. CREATED : 컨테이너가 생성된 시간이다.
  5. STATUS : 컨테이너의 상태이다. 실행중은 Up, 종료는 Exited, 일시정지는 Pause로 나온다.
  6. PORTS : 컨테이너가 개방한 포트와 호스트에 연결한 포트이다. 특별한 설정을 하지 않았기에 출력되지 않았다.
  7. NAMES : 컨테이너의 고유한 이름이다.
    • 컨테이너 생성시 --name 옵션으로 이름을 설정하지 않으면 도커 엔진이 임의의 형용사와 명사를 조합해 설정한다.
    • ID와 마찬가지로 중복이 안되고 docker rename 명령어로 이름을 변경할 수 있다. ex. docker rename original-name, changed-name

위의 결과와 다르게 원하는 항목만 볼 수 있는 방법도 있다.
docker ps --format 'table{{.Names}}\ttable{{.Image}}' 커맨드를 입력하면 된다.

  • \t는 tab을 의미한다.

그렇다면, 꺼져있는 container를 확인하기 위해선 어떻게 해야할까?

docker ps -a 커맨드를 입력한다. -a는 all을 의미한다.

도커 컨테이너의 생명주기에 대해서도 알아보자

도표로 보자면 다음과 같다.

우선, 생성부터 실행까지 알아보자

현재까지 사용해온 docker run <이미지 이름> 명령어가 아닌, docker createdocker run으로 쪼개서 봐보자...

docker run <이미지 이름> = docker create <이미지 이름> + docker start <컨테이너 아이디/이름>

  • docker create <이미지 이름>

    - create 실행 시, 이미지에 있는 파일 스냅샷을 하드 디스크에 넣어준다.

  • docker start <컨테이너 아이디/이름>

    - 시작시 실행 될 명령어까지 컨테이너에 들어가게 되며, 컨테이너가 실행된다.

예시를 통해서 봐보자!

docker create 이미지 이름 입력 시 컨테이너 ID가 생성된다.
docker start -a 컨테이너ID 입력 시 hello-world가 실행된 걸 볼 수 있다.

  • -a 는 attach 옵션을 의미한다.
  • 만약 -a 옵션 없이 실행을 한다면 다음과 같은 결과를 얻는다.
  • -a 옵션은 도커 컨테이너가 실행될 때 output을 화면에 출력해주는 역할을 한다.

이번에는 중지 부분에 대해서 알아보자.

실행하다가 중지를 할 때는 두 가지 커맨드로 중지할 수 있다.
docker stop <중지할 컨테이너 아이디 / 이름> 혹은 docker kill <중지할 컨테이너 아이디 / 이름>
그렇다면, Stop과 Kill은 어떤 차이가 있을까?
공통점부터 살펴보자면 둘다 실행중인 컨테이너를 중지시킨다는 점이다.
차이점으로는 다음과 같다.

  • Stop
    - Stop은 Gracefully하게 중지를 시킨다.
    - 예를 들어, 메시지를 보내고 있었다면 보내고 있던 메시지의 전송까지 완료하고 컨테이너를 중지시킨다.

  • Kill
    - Kill은 Stop과 달리 어떠한 것도 기다리지 않고 바로 중지시킨다.


stop은 SIGTERM을 날려 Grace Period를 준다.

마지막으로, 컨테이너 삭제에 대해서 알아보자

컨테이너의 삭제는 docker rm <아이디/이름>을 입력하면 된다.

  • 실행중인 컨테이너는 먼저 중지를 한 후에 삭제가 가능하다.

만약 모든 컨테이너를 삭제하고 싶다면 docker container prune를 입력하면 된다. (docker 1.13.x 이후 버전에서 사용가능하다.)

그리고, 이미지를 삭제하고 싶다면 docker rmi <이미지 id>를 입력하면 된다.

마지막으로, 한번에 컨테이너, 이미지, 네트워크 모두 삭제하고 싶다면 docker system prune을 입력하면 된다.

  • 도커를 쓰지 않을때 모두 정리하고 싶을때 사용해주면 좋다.
  • 실행중인 컨테이너에는 영향을 주지 않는다.

실행중인 컨테이너에 명령어 전달하려면?

이미 실행중인 컨테이너에 명령어를 전달하고 싶다면?
순서는 다음과 같다.

  1. 먼저 2개의 터미널을 실행한다.
  2. 첫 번째 터미널에서 컨테이너 하나를 실행한다.
  • docker run alpine ping localhost 명령어를 입력하였다.
  1. 두 번째 터미널에서 컨테이너가 잘 작동하고 있는지 확인하고 다른 명령어를 전달한다.
  • docker ps 명령어로 컨테이너의 아이디를 확인한 후, docker exec <컨테이너 ID> ls를 이용하여 명령어를 전달한다.

docker run vs. docker exec

  • docker run은 새로 컨테이너를 만들어서 실행하는 것이다.
  • docker exec은 이미 실행중인 컨테이너에 명령어를 전달하는 것이다.

이번에는 레디스를 도커 환경에서 실행을 해보자.

레디스를 도커환경에서 실행하여 컨테이너에 대해 이해해보자.

위 그림과 같이 먼저 레디스 서버를 실행 후, 레디스 클라이언트를 통해서 서버에 명령어를 전달해줘야 한다.
순서는 다음과 같다.

  1. 두 개의 터미널을 실행한다.

  2. 첫 번째 터미널에 레디스 서버를 작동 시킨다. docker run redis

  3. 두 번째 터미널에서는 레디스 클라이언트를 작동시킨다. redis-cli

그러나, redis-cli를 입력할 경우 에러가 발생한다.
이유는 다음과 같다. 레디스 클라이언트가 레디스 서버가 있는 컨테이너 밖에서 실행하려고 하니 레디스 서버에 접근할 수 없기 때문에 에러가 발생하는 것이다. 그림으로 보면 다음과 같다.

그렇다면, 어떻게 해결해야 할까?

바로, 레디스 클라이언트도 컨테이너 안에서 실행할 수 있도록 하는 것이다.
다시 두 번째 터미널로 돌아가서 docker exec -it <컨테이너 아이디> redis-cli를 입력하면 된다.

  • -it : interactive terminal의 약자로, -it를 붙여줘야 명령어를 실행 한 후에 계속 명령어를 적을 수 있다.
    - 만약 -it 옵션이 없다면 redis-cli를 실행한 후 밖으로 다시 튕겨져 나온다.

컨테이너를 쉘 환경으로 접근해보자

지금까지 실행중인 컨테이너에 명령어를 전달할때는
docker exec -it <컨테이너 ID> 명령어를 입력하여 번거로움이 있었다.

그러나, 이러한 문제점을 해결하기 위해 컨테이너 안에 쉘이나 터미널 환경으로 접속을 할 수 있다.
바로, docker exec -it 컨테이너 아이디 sh를 입력하는 것으로
마지막 명령어를 sh로 주면 된다.

  1. 먼저 첫 번째 터미널을 실행 한 후, alpine 이미지를 이용해서 컨테이너를 실행한다.
  2. 그 후, 두 번째 터미널에서 exec을 이용해서 마지막 명령어 부분에 sh를 입력 후 컨테이너 안에서 터미널 환경을 구축한다.
  3. 그 안에서 여러가지 명령어를 입력해 볼 수 있다.

추가적으로, exec 대신에 run도 사용 가능하다.

마지막으로, 쉘 환경에서 빠져나올 땐 ctrl+D를 누르면 된다.!

profile
Pay it forward.

0개의 댓글