볼륨연결

볼륨연결은 폴더를 연결한다고 생각하면 된다.(링크)

호스트의 폴더를 컨테이너의 디렉토리에 마운트해서 호스트에서 해당 폴더에 파일을 생성,삭제,수정을 하면 컨테이너에 바로 적용되도록 할 수 있다.

 

보통 이미지에 들어있는 os들은 최소설치이기 때문에 vi, sudo 같은 명령어가 안되는 경우가 많아서 호스트에서 직접 파일을 수정해서 넣어주면 더 편리한 경우가 많다!

 

 

실습 (목표 : 기본적으로 제공되는 index.html 수정)

1. 아파치 컨테이너 실행 (볼륨 연결X)

docker run -d httpd
docker exec -it [CONTAINER ID] bash

index.html 파일은 /usr/local/apache2/htdocs 에 위치해있다. 해당 파일을 수정하면 웹서버(아파치)에 접근했을 때 나오는 기본 페이지를 변경할 수 있다.

vi나 sudo 같은 명령어가 없다고 나온다.

 

 

2. 볼륨을 연결한 아파치 컨테이너 실행 (볼륨 연결O)

//볼륨에 연결하기 예제
docker run -d -v [HOST_PATH]:[CONTAINER_PATH] [IMAGE]
//볼륨 연결 실습
docker run -d -p 9097:80 -v /home/docker_mount/lecture:/usr/local/apache2/htdocs --name=myHttpd httpd

-v(volume)옵션을 통해 HOST ↔ CONATINER 간 디렉토리를 손쉽게 마운트 할 수 있다.

 

해당 상태에서 웹서버에 접근하면 HOST디렉토리에는 아무것도 없으므로 아래와 같은 화면이 나온다. (기본적으로 생성되는 index.html은  It works! 문구가 표시되도록 되어있다.)

이제 호스트OS에서 설정해둔 디렉토리 (/home/docker_mount/lecture)에 가서 index.html을 생성해보자.

cd [볼륨마운트한 경로]
vi index.html

호스트OS에서 생성한 index.html

 

이렇게 파일을 생성한 후 아파치 서버에 접속해보면 아래와 같이 잘나오는 것을 확인할 수 있다.

 

 

정리 : 호스트OS와 컨테이너간 디렉토리 마운트를 위해서는 볼륨을 이용하자. (docker run -v [HOST]:[CONTAINER])

attach로 접근할 수 없는 경우

OS만 있는 컨테이너와 다르게 다른 command가 있는 컨테이너들은 단순히 attach로 리눅스 쉘에 접근할 수가 없다.

docker run -d -p 8080:80 httpd

이렇게 컨테이너를 실행시킨 후 

docker attach [방금실행시킨 httpd ID]

attach 명령어로 리눅스 쉘에 접근하려고 하면 접근이 안된다.

run할 때 -it를 붙이지도 않았을 뿐더러 실행되고 있는 명령어가 /bin/bash가 아니라 httpd-foreground 이기 때문.

 

그렇다면 실행할 때 -it 옵션을 준다면?

docker run -dit httpd
docker run -dit httpd bash

 

이렇게 실행해서 docker attach를 하면 어떨까? 컨테이너가 바로 종료되어버린다.

두번째 줄에있는 bash명령어를 줘도 마찬가지.

 

다른 명령어가 실행되고 있을 때 터미널에 접근하고 싶다면?

docker exec -it [CONTAINER_ID] bash

exec -it 명령어로 해결 할 수 있다. 상호작용할 수 있는 bash를 실행시켜준다.

옵션인 -it의 의미는 이전 강의에와 마찬가지인것 같다.

-i : interactive 상호작용

-t : terminal 모드 /bin/bash로 상호작용한다.

 

 

 

 


정리
1. os(ubuntu) 이미지일 때 터미널 실행 법
docker run -dit ubuntu
docker attach [CONTAINER_ID]

2. while process (httpd) 이미지 일 때
docker run -d -p 8080:80 httpd (docker run -dit를 해도 상관없음)
docker exec -it [CONTAINER_ID] bash

도커는 이미지 실행 시에 command를 지정하게 되어있는데 아파치같은 것은 아파치 실행 명령어가 command여서 attach로 접근하면 bash 접근불가.
이럴 때는 docker exec -it [CONTAINER_ID] bash 로 상호작용할 수 있도록 해주면 된다.

docker run 명령어와 자주 쓰이는 옵션들 정리

우분투 컨테이너 다운로드 및 실행

docker run -d --name myubuntu ubuntu

run을 한 다음 docker ps 를 했을 때 실행 중인 우분투 컨테이너가 보일 줄 알았지만 해당 컨테이너는 실행과 동시에 종료되어 docker ps -a를 해야만 볼 수 있다.

 

우분투 컨테이너가 실행과 동시에 종료되는 이유

https://ilikecoding.tistory.com/78

 

도커 입문 6강. 컨테이너 실행하기

컨테이너 특징(생명주기 관련)컨테이너 내부에 프로그램이 일회성 이라면 컨테이너를 띄우자마자 종료되어버린다.즉, 컨테이너에서 실행될 프로그램이 데몬처럼 백그라운드에 떠있으며 무언

ilikecoding.tistory.com

6강에서도 설명하셨는데.. 컨테이너 내부 프로그램이 일회성이라면 컨테이너를 띄우자마자 종료되어버린다고함.

 

 

우분투 이미지는 내부에 실행될 프로그램이 없기 때문에 바로 종료.. httpd는 내부에 아파치 프로그램이 무한루프로 돌고 있기 때문에 종료되지 않는다.

 

[우분투 이미지 실행]

우분투 ▶ RUN ▶ 죽음(내부에 실행할 프로그램이 없다.)

[httpd 이미지 실행]

httpd ▶ RUN ▶ 내부에 무한루프로 Listener가 돌고있어서 종료되지 않는다.
httpd image = ubuntu + apache 인 것.

 

우분투 이미지 종료를 막는 방법

docker run -dit --name myubuntu ubuntu

바로 -it 옵션을 사용하는 것이다.

-i : interaction 상호작용을 하겠다.

-t : terminal 터미널 모드로 사용 (/bin/bash를 자동으로 실행시켜준다.)

--name : 도커 컴포즈를 할 때 컨테이너끼리 결합을 할 때 --link 옵션의 파라미터로 컨테이너 이름을 넘겨주기 위한 식별값.

(도커 컴포즈 뿐만 아니라 하나의 이미지로 여러 컨테이너를 띄울수도 있는데 각각 컨테이너 마다 붙일 수 있는 식별값으로 생각하면 될것 같다.)

 

 

우분투를 해당 옵션으로 다시 실행하기 위해서는 일단 전에 바로 종료되었던 컨테이너를 삭제해야한다.

docker rm $(docker ps -a -q --filter name=myubuntu)

 

실행중인 컨테이너에 접근하는 명령어

docker attach [CONTAINER ID]

-it 옵션으로 컨테이너를 실행하면 /bin/bash프로그램이 실행되는데 그때 우분투에 접속해서 bash 프로그램과 상호작용할 수 있는 명령어이다.

도커 이미지 삭제 프로세스

실행 중인 컨테이너 중지(stop) ▶ 중지된 컨테이너 삭제(rm) ▶ 이미지 삭제 (rmi)

 

실행중인 컨테이너 확인 후 종료 및 삭제

docker ps
docker stop [CONTAINER ID]
docker rm [CONTAINER ID]

중지된 컨테이너 확인 및 삭제

docker ps -a
docker rm [CONTAINER ID]

이미지 확인 및 삭제

docker images
docker rmi [IMAGE ID]

 

(이미지를 삭제하기 위해선 해당 이미지로 실행중 이거나 중지된 컨테이너가 없어야 한다.)

 

위와 같은 프로세스는 많은 이미지를 지울 때 너무 많은 것을 반복해야한다.

#실행중인 모든 컨테이너 종료
docker stop $(docker ps -q)
#중지된 컨테이너 모두 삭제
docker rm $(docker ps -a -q)
#모든 이미지 삭제
docker rmi -f $(docker images -q)

※ $(docker ps -a -q)

$()로 감싸면 변수의 값으로 취급한다. docker ps -a -q 결과값을 docker stop의 입력값으로 취급한다는 이야기이다.

-q옵션 : IMAGE나 CONTAINER의 ID만을 반환하는 옵션

--filter name 옵션 --filter name=jenkins 처럼 --filter name 옵션을 활용하면 내가 원하는 값만 필터링할 수 있으니 잘 사용해보자.

 

포트포워딩하기

docker run -d #detach의 약자로 백그라운드에서 작동하도록 하는 옵션 (daemon으로 외워도 될듯하다)
docker run -p #port를 지정해주는 옵션으로 "HOST:CONTAINER" 형식으로 나열
docker run -d -p 8080:80 httpd #호스트의 8080으로 접근하면 컨테이너 80포트로 전달해준다

 

현재 나의 구성도

[인터넷] - KT공유기 - DMZ - IPTIME공유기 - H2서버

 

Apache 컨테이너 실행하기

docker run -d -p 9096:80 httpd

이제 호스트OS로 9096으로 요청하면 아파치 컨테이너의 80포트로 연결해주게 된다.

원격지에서 실험해보니 정말 잘동작한다.

원격지:9096 ▶ 인터넷 ▶ KT공유기 ▶ DMZ ▶ IPTIME공유기 ▶ 9096포트를 H2:9096으로포트포워딩 
▶ H2서버9096 ▶ httpd컨테이너

이렇게 되어있는 건데 iptime공유기에서 외부의 9096을 내부의 9096으로 설정해놔서 가능하다.

KT공유기와 iptime공유기는 DMZ설정이 되어있어서 모든 요청을 IPTIME공유기로 통과하도록 설정해놨다.

 

Apache 컨테이너 실행하기

docker run -d -p 9096:80 httpd

이제 호스트OS로 9096으로 요청하면 아파치 컨테이너의 80포트로 연결해주게 된다.

 

Nginx 컨테이너 실행하기

docker run -d -p 9097:80 nginx

apache나 nginx나 같은 80포트를 사용하지만 HostOS에서 포트포워딩을 해주니까 상관없다는 점이 정말 좋은거 같다.

9096으로 접근하면 httpd 80

9097로 접근하면 nginx 80

 

 

※ docker run을 할 때 로컬에 저장되지 않은 이미지를 지정하면 도커허브에서 자동으로 pull해서 run을 해준다.
즉, docker run nginx를 하였을 때, 로컬에 nginx이미지가 있으면 있는것을 사용하고 없으면 자동으로 도커허브에서 다운로드받아서 run해준다.

 

 

 

 

 

 

 

 

 

컨테이너 특징(생명주기 관련)

컨테이너 내부에 프로그램이 일회성 이라면 컨테이너를 띄우자마자 종료되어버린다.

즉, 컨테이너에서 실행될 프로그램이 데몬처럼 백그라운드에 떠있으며 무언가를 처리하는 종류가 아니라 어떤 일을 끝마치고 종료되는 프로그램이라면 컨테이너도 그 프로그램이 종료되면 같이 종료되어버린다고 한다.

 

명령어

이미지 다운로드 (테스트를 위해 tomcat)

docker pull tomcat

컨테이너 실행하기

docker run tomcat # 포그라운드로 컨테이너가 실행된다.

 

컨테이너 백그라운드로 실행하기

일반적으로 docker run tomcat같은 명령어로 실행하면 컨테이너가 포그라운드로 실행되어 해당 터미널에서는 어떤한 작업도 할 수 없게 된다. (또한 해당 터미널 접속이 끊어지면 실행중이던 컨테이너도 중지되므로 매우 불편하다.) 그래서 대부분 컨테이너를 실행할 때는 백그라운드 모드로 실행한다.

docker run -d [IMAGE ID]

 

컨테이너가 정상적으로 실행되고 있는지 확인하기 (실행중인 컨테이너, 중지된 컨테이너 두 개다 확인하는 방법)

docker ps #현재 실행중인 컨테이너 확인
docker ps -a #실행중이거나 중지된 컨테이너까지 모두 확인

컨테이너를 중지시키는 방법

docker stop [CONTAINER ID]

도커에서 실행중인 톰캣으로 접근이 안되는 이유

도커에 톰캣을 띄워놓고 호스트OS나 다른 곳에서 localhost:8080 을 해도 도커에 실행중인 톰캣에 접근이 안되는 이유는 도커와 호스트OS는 다른 네트워크 대역을 사용하고 있기 때문이다.

만약에 도커에 있는 톰캣으로 접근하고 싶다면 호스트OS에서 도커로 접근하는 요청에 대해 포트포워딩을 해줘야 한다.

 

이미지 다운로드

docker pull [이미지:태그]

(보통 태그는 버전을 명시하는 것 같다. 태그를 입력하지 않으면 최신버전을 다운로드한다.)

 

이미지 확인

docker images

 

현재 실행중인 컨테이너 확인

docker ps // 중지된 것은 보이지 않고, 실제로 실행중 인것만 보인다.

docker ps -a // 중지된 컨테이너도 모두 보인다.

 

이미지 삭제하기 

현재 실행중인 컨테이너 혹은 중지된 컨테이너인 경우 삭제할 수 없다.

docker rmi [IMAGE ID] 

docker rmi [REPOSITORY]

 

이미지 실행시키기 (컨테이너로 띄운다)

docker run 

컨테이너 중지하기 (실행중인 것을 중지)

docker stop [CONTAINER ID]

컨테이너 삭제하기 (종료된 것을 삭제)

docker rm [CONTAINER ID]

 

 

기억할 것

  • 컨테이너의 상태는 2가지가 있다. 
    • 실행중 : docker ps 로 확인 가능
    • 중지중 : docker ps -a 를 해야 비로소 확인 가능
  • 컨테이너라는 의미는 메모리에 할당된 프로세스 상태라는 상태인데 docker stop 명령어로 중지 했는데 계속 프로세스 상태인것일까? 라는 의문에는 나중에 설명해주신다고 한다.
  • 이미지를 삭제할 때는 컨테이너로 띄워져 있을 때는 삭제할 수 없다. (중지된 컨테이너라도 docker rm 으로 아예 컨테이너에서 지워줘야 이미지를 삭제할 수 있다.)

 

가상화 vs 컨테이너(도커)

가상머신과 도커는 리얼 머신이 아니라는 점에서 비슷하지만 작동 방식에서 차이를 보인다.
가상머신은 편하긴 하지만 성능이 좋지 못하다. (CPU에 가상화를 위한 기능들이 많이 들어갔지만 아직도 리얼머신에 비해 많이 느리다.)

 

전가상화와 반가상화

전가상화의 성능 개선을 위해 개발된 반가상화가 널리 쓰이고 있다.

 

가상화 계층도

가상 머신 자체는 완전한 컴퓨터이기 때문에 게스트 OS를 항상 설치해야한다. 그래서 이미지 용량이 커진다.

 

도커 계층도

가상화와 달리 도커는 게스트 OS를 설치하지 않고 OS자원은 호스트와 공유하는 방식이다. 이미지 용량이 크게 줄어들었으며 HW 가상화 계층이 없기 때문에 메모리 접근, 파일시스템, 네트워크 속도가 가상 머신에 비해 월등히 빠르다.

 

도커는 이미지 버전을 관리할 수 있고 저장소(docker hub)에 이미지를 업로드하거나 다른 이미지를 다운로드 받을 수 있는 등 배포에 특화된 기능을 제공해준다.

 

리눅스 컨테이너

LXC는 컴퓨터를 통째로 가상화하여 OS를 실행하는 것이 아닌 리눅스 커널 레벨에서 제공하는 일종의 격리된 가상 공간이다. 이 기상공간은 OS가 설치되지 않기 때문에 가상머신이 아닌 컨테이너라고 부른다.

 

리눅스 커널의 ControlGroups(cgroups)는 CPU, 메모리, 디스크, 네트워크 자원을 할당하여 완전한 형태의 가상공간을 제공한다. 또한 프로세스 트리, 사용자 계정, 파일시스템, IPC등을 격리시켜 호스트와 별개의 공간을 만든다. (chroot 명령어처럼) 이것을 Namespace isolation(namespaces) 라고 한다.

 

LXC는 리눅스 커널의 cgroups와 namespaces기능을 활영하여 가상 공간을 제공한다.

 

LXC의 구조

LXC는 격리된 공간만 제공할 뿐 개발 및 서버 운영에 필요한 부가 기능이 부족한데, docker는 리눅스 커널의 cgroups와 namespaces를 기반으로 하여 이미지, 컨테이너 생성 및 관리 기능과 부가기능을 제공한다.

 

따라서 컨테이너는 리눅스 커널을 기반으로 하기 때문에 윈도우에서 도커같은 컨테이너 기술을 사용하기 위해서는 리눅스 하위시스템이 필요하다. (wsl2나 따로 설정이 필요)

 

docker 명령어 전송방식

  1. Host OS에서 docker container에 명령어 전송
  2. docker daemon이 명령어를 받아서 container에게 전달해준다.

컨테이너 vs 이미지

이미지 

도커에서 실행되지 않고 있는 서버운영에 필요한 소스코드, 라이브러리 등이 셋팅된 상태의 일종의 프로그램 상태
(프로그램은 하드디스크에 저장되어있는 실행되고 있지 않은 상태를 의미하기도하니까)
(이미지는 특정 프로세스를 실행하기 위한 모든 파일과 설정, 의존성을 해결한 상태로 Ubuntu이미지는 Ubuntu를 실행하기 위한 모든 파일을 가지고있다.)

 

컨테이너

이미지를 실행시켜 메모리에 로딩한 상태

도커의 역할

1. 컨테이너 생성

2. 컨테이너 관리 및 컨테이너 내부에 프로그램 설치 가능

3. 컨테이너 실행

 

도커 컴포즈

여러 컨테이너를 결합하여 실행할 수 있게해주는 도구

 

도커 허브

github와 비슷한 개념으로 개인이나 기관이 만든 컨테이너를 업로드하여 공유할 수 있는 클라우드 저장소 (레포지ㅌ리)

도커 등장배경

교역을 위한 항구와 배가 있다고 가정하자.
컨테이너가 발명되기 전에는 트럭으로 전달된 짐들을 모두 내린 후 다시 배에 적재 시키는 작업을 위해 엄청난 노력이 들었을 것이다.

(트럭에서 짐을 내린다 -> 내린 짐을 배에 싣는다.)


해당 작업에서 딜레이가 생기면 짐을 싣고 온 다른 트럭들은 모두 대기해야하는 상황이 생긴다.

이 병목현상을 해결하기 위해 컨테이너라는 것을 두면 각종 짐을 싣고있는 컨테이너만 옮기면 되기 때문에 작업이 굉장히 쉬워진다.

(크레인으로 컨테이너만 배로 옮겨버리면 되기 때문에 작업량 감소 효과!)

도커란?

컨테이너 관리 시스템 


도커 vs 현실 컨테이너

SW(jdk, python 등) 짐(컨테이너 안에있는)
OS 컨테이너
인프라(컴퓨터)


도커 컴포즈

컨테이너끼리의 상호작용을 가능하게 하는 관리 도구
(여러 컨테이너를 하나의 어플리케이션으로 동작할 수 있도록 해준다.)

도커의 특징

WORA (Write Once Run Anywhere) : 컨테이너를 한번 잘 만들어놓으면 다른 컴퓨터에서도 동일하게 작동한다.

+ Recent posts