본문 바로가기
Development(Web, Server, Cloud)/22) LINUX - Cloud

클라우드 41일차(가상화, Docker, Dockerfile)

by tonyhan18 2022. 3. 3.
728x90

가상화 : 서버 가상화(하이퍼바이저)

하이퍼바이저는 물리 자원에 접그나여 추상화 작업(물리자원 -> 논리자원) 을 거치고 이를 통해 vResources를 생성함. 이를 조합하고 연결하고 완전한 하나의 서버로 서비스를 제공하는 것은 '가상화'라고 함

성능 저하가 필수요소 -> 무중단 서비스, 지역간 이동, 유연한 리소스 제공

 

클라우드 환경에서 가상화는 필수요소

클라우드 == '빌려쓰기 -> 빌려쓰는 것에 따라서 클라우드의 종류가 달라짐

- IaaS(Infra Structure as a Service) : 환경/시설을 제공 (AWS)

- PaaS(Platform as a Service) : 개발 환경을 제공 (도커), google app engine

- SaaS(Software as a Service) : (salesforce, SAP)

 

서버 가상화의 가장 큰 단점은 성능저하(local 보다 30% 성능감소)

-> Docker

 

OS의 커널 안에는 두가지(cgroup, namespace)가 존재한다. 이걸 도커가 사용한다.

namespace : 작업 구획 나누기 -> 사용자별로 각자의 vi 작업하기

group : 물리자원을 각 프로세스 별로 다르게 할당할 수 있음 -> 애플리케이션간 영향을 주지 않도록 막는다 == 컨테이너를 둔다

 

컨테이너도 두가지 종류가 존재

1. App - mariadb, httpd, nginx, jenkins, node.js, python를 자신이 원하는 버전으로 설정 가능

2. OS - App 위치에 os를 집어넣는 방식 -> CentOS, Fedora 등등... -> 커널은 호스트 OS 커널을 사용함.

 

도커 컨테이너 라이프 사이클(생성, 수정, 삭제)

* DB APP 배포 -> 이미지 저장소

- 로컬저장소 : 자신의 PC

- 원격저장소 : public -> 접근제한 없이 사용 가능/ private -> 제한인원만(인증필)

 

public에서 사용한다면 docker-hub에서 특정 버전을 땡기어서 사용가능해진다.

```

docker pull mariadb:10.4

```

 

컨테이너 생성

- create -> 컨테이너 생성 -> start

- run -> 컨테이너 생성 + 실행

-> 재실행하고 싶다면 reboot/중지하고 싶다면 stop

* 주의할점 : 한번만들면 수정하지 못함

 

---

실습

```

docker login  # 필수

sudo cat /home/user1/.docker/config.json #유저 토큰 발급됨

docker container run -it --name centos01 --hostname centos1 centos:7 /bin/bash

```

빠져나올때

1. Ctrl + D(exit) -> 컨테이너 종료후 빠져나옴

2. Ctrl + P -> Ctrl + Q -> 컨테이너가 백 그라운드에서 계속 실행

-i(입출력가능)

-t(터미널)

--name(원하는 이름 넣기)

 

docker container inspect

 

실제 OS 입장에서 컨테이너는 하나의 애플리케이션이므로 각 애플리케이션(컨테이너)이 실행되면 애플리케이션 별로 1개의 PID(Process ID)가 할당됨

 

 

우분트 OS 위에 컨테이너들을 연결하기 위한 기본네트워크가 있는데 그게 docker0(172.17.0.1)이다. 거기에 컨테이너들이 docker0를 DG로 생각해서 연결한다. 그리고 docker0는 NAT로 동작하게 된다.

 

이미지에 보면 이상한 이름이 들어가 있다. 이게 생긴이유는...

이미지의 경우 동일한 centos:7 이라고 하더라도 나중에 업데이트가 된 centos:7 과 기존 centos:7은 차이가 있을 수 있다. 즉 조그마한 업데이트까지 잡아내기 위해서이다.

도커 네트워크의 기본 드라이버

```

docker network ls

```

 

bridge : 실제 ubuntu의 주소와 동일한 대역의 주소를 컨테이너에 할당한다.

host : 일반 가상화에서는 지원되지 않는 옵션으로 호스트(ubuntu)의 IP 주소를 컨테이너에 할당하고 동일하게 사용하고자 하는 경유에 사용(거의 사용하지 않음)

none : 컨테이너에 NIC이 없는 상태 -> 네트워크 안쓰겠다.

overlay : 클러스터 환경에서 사용되는 드라이버이고 클러스터링 되어 있는 호스트끼리 동일 사설 네트워크를 사용할 수 있음. 클러스터를 묶고 네트워크를 만들면 자동으로 overlay가 만들어진다.

 

 

 

```

docker container inspect --format='{{.LogPath}}' 이미지ID

```

JSON 형태로 데이터를 받다보니 위와같이 {{.LogPath}}와 같은 형태로 데이터 일부만 출력가능하다.

 

이를 활용해서 IPAddress만 나오게 만들 수 있다.

```

docker container inspect --format='{{.NetworkSettings.Networks.bridge.IPAddress}}' 5adde526daf2

```

 

컨테이너를 이용하여 웹서버를 실행시키는 방법

1. 애플리케이션 컨테이너를 활용하는 방법

2. OS 컨테이너 내에 웹서버를 설치하고 이를 통해 서비스 하는 방법

 

OS 컨테이너를 이용하여 웹서비스를 제공하고자 한다면 기본 홈 디렉토리는

/var/www/html이 됨

 

위와같이 우분트가 있고 여기안에 디렉토리가 두개 있다고 하자. 이 디렉토리는 nginxhtml과 httpdhtml이다. 이때 컨테이너를 우분트에 있는 디렉토리에 마운트하자는 것이다. 그리고 컨테이너를 따라 외부에 서비스를 제공하는 것이다.

 

하지만 애플리케이션 컨테이너를 활용하고자 할 경우에는 기본 홈디렉토리가 /var/www/html이 아니라 아래와 같다.

nginx -> /usr/share/nginx/html/index.html

httpd -> /usr/local/apache2/htdocs

 

```

docker container run -d --name nginx01 -p 8001:80 -v /home/user1/nginxhtml/:/usr/share/nginx/html nginx

docker container run -d -p 8006:80 --name httpd06 -v /home/user1/nginxhtml:/usr/local/apache2/htdocs httpd

```

볼륨연결을 해주자. 마운트를 위해 내 폴더와 이미지의 폴더를 적어주자.

 

컨테이너에게 볼륨, 디렉토리를 제공하는 옵션 : -v

-v 는 마운트, volume을 블럭형태로 제공하는 두가지 방법

1. 마운트

-v /home/user1/nginxhtml:/usr/share/nginx/html

우분투의 /home/user1/test 디렉토리와 컨테이너의 /usr/share/nginx/html을 마운트

 

2. 블럭스토리지(volume을 생성하고 해당 볼륨을 컨테이너의 /dev/sda3 와 같은 형태로 제공)

 

```

docker container prune  # 멈춰 있는 컨테이너들 삭제

docker volume prune  #멈춰 있고 사용안되는 볼륨 삭제

docker system prune  # 멈춰 있는 컨테이너/연결안된 네트워크/사용안되는 이미지, 캐시 삭제

```

 

```

docker volume create --name testvolume1

docker volume ls

```

-d : 로컬 쓸꺼냐 원격 쓸거냐

 

대충 이런 방법들이 있는데 일단 그렇다고 생각하고 넘어가자

 

```

docker container run -it -v testvolume1:/root centos:7 /bin/bash

```

 

이미지를 만들어보자

```

docker image ls

docker image tag centos:7 tonyhan18/mycentos:1.0

```

하면 나만의 이미지가 만들어진다. 하지만 두개는 같은 이미지이다. 왜냐하면 IMAGE ID가 같아서이다.

 

왜 똑같은것을 쓰냐면 docker hub에 base image가 존재하는데 이걸 수정안하고 그냥 docker hub에 다수가 올린다고 생각해보자. 그런데 이 base image에 뭔가 수정해서 올리면?

 

base image에 추가적으로 일부분을 추가했을때 이걸 통째로 저장하면 docker hub가 감당못하기 때문에 [원본데이터 + 추가데이터] 해서 docker hub에 올리면 추가된 데이터만 저장된다.

그래서 이미지는 계층구조를 가진다.

 

```

docker image inspect centos:7

```

 

centos:7인데도 불구하고 우리의 이미지가 보인다.

 

레이어가 보인다.

 

한번 실재로 docker hub에 우리의 이미지를 올려보자

 

```

docker push tonyhan18/centos:1.0

```

으로 서버에 우리가 만든 이미지를 올릴 수 있다.

주의할점은 올릴때 repository와 같은 이름의 파일만 받아주고

이름이 다르면 public 공간을 새로 만들어서 업로드해준다.

 

컨테이너 생성시 시스템 환경변수 선언도 가능하다 -e 옵션사용

시스템 환경변수는 사용자가 로그인하게되면 시스템 내에서 사용할 수 있는 다양한 기본 설정 정보를 담은 변수를 의미하며, PATH, USER, HOSTNAME, SSH 등과 같은 정보를 담는다.

시스템 환경변수는 시스템 내의 어느 곳에서든 적용할 수 있다.

 

-w : working directory를 의미하며 처음 컨테이너로 접속하면 해당 디렉토리로 이동한다. 지정되지 않았을 경우네는 기본적으로 `/`로 이동한다. -w는 실제로 컨테이너 내에 존재하지 않은 디렉토리를 지정할 수 있다.

 

```

docker container run -it -v /home/user1/nginxhtml:/root -w /testdir -e WORKDIR=/testdir centos:7 /bin/bash

```

pwd <-- 현재위치

echo $WORKDIR <-- 환경변수

/dev/sda5  <-- 마운트된 정보

 

diff 를 사용해서 컨테이너 안에 어떤 조작을 했는지 확인할 수 있다.

 

삭제

```

docker container rm -f $(docker container ls -aq)

docker container rm -f $(docker volume ls -aq)

```

 

도커 컨테이너 이미지

Dockerfile의 작성

자신만의 이미지를 만드는 대표적인 방법

- Dockerfile을 이용한 생성

도커파일은 텍스트파일이며 도커가 해당 텍스트의 내용을 기반으로 새로운 이미지를 생성하게 된다.

 

```

cd ; mkdir docker ; cd docker

touch Dockerfile  # 이름이 틀리면 안된다

 

```

 

FROM ubuntu:18.04
RUN apt-get update -y
RUN apt-get install nginx -y
COPY index.html /var/www/html/index.html
CMD nginx -g 'daemon off;'  # daemon off를 하지 않겠다

FROM(필) : 베이스 이미지 지정 -> 로컬 저장소를 먼저 확인후 없으면 remote에서 가져온다

예전에는 MAINTAINER을 이용해서 이미지 제작에 대한 설명 적음. 현재는 LABEL을 이용하여 이를 대체함

 

LABEL(선택) 은 주석처럼 사용되지만 이미지 안에 들어는 감

 

RUN : 이미지내에서 실행할 명령어들, RUN은 Dockerfile 내에서 여러번 사용가능

 

COPY는 로컬에 있는 특정 파일, 디렉토리를 이미지로 복사함

(ADD는 COPY와 비슷하다. COPY의 모든 기능을 포함한다. 원격지에 있는 파일을 붙여넣기도 가능)

 

CMD 와 RUN은 둘다 대부분 명령실행이 주가 되지만 RUN은 이미지에서 실행한다.

CMD는 이미지가 아니라 컨테이너로 배포될 때 실행하는 명령어다.

CMD는 RUN과 달리 Dockerfile 내에서 1번만 사용가능 -> 여러개의 명령어를 사용하기 위해서는 쉘을 이용하면된다. -> 쉘을 복붙하고 실행시키면 된다.

[ CMD /bin/bash install.sh ]

 

```

docker build -t mynginx:1.0 .  #현재 위치에 있는 도커파일로 만들겠다

```

t는 필수요소, mynginx는 이미지 이름

1.0은 버전명인데 우리가 원하는걸 쓰면 된다.

. 은 Dockerfile의 위치이다. 현재 디렉토리에 있는 Dockerfile의 내용을 읽어 이미지를 만들어라

Dockerfile명이 아니면 `-f` 옵션을 사용해서 지정가능

일반적으로 여러 이미지를 만들고자 한다면 이미지 별로 별도의 디렉토리를 생성하고 각 디렉토리에서 Dockerfile을 작성한다.

 

만든 이미지를 실행해보자

```

docker container run -d -p 8001:80 mynginx:1.0

```

접속이 잘된다.

 

Quiz. CentOS:7 이미지를 이용하여 mycentos:1.0을 생성한다.

해당 이미지는 httpd가 설치되고 로컬에 있는 index.html파일을 컨테이너의 홈디렉토리에 복사하여 컨테이너 실행시 즉시 웹페이지가 보여야 한다.

 

FROM ubuntu:18.04  # FROM 베이스 이미지 지정
RUN apt-get update -y
RUN apt-get install apache2 -y
COPY index.html /var/www/html/index.html
EXPOSE 80
CMD /usr/sbin/apache2ctl -D FOREGROUND

# 선생님 ver
FROM centos:7
RUN yum update -y
RUN yum install httpd -y
COPY index.html /var/www/html/index.html
EXPOSE 80 8080
CMD httpd -D FOREGROUND

만약 실제로 컨테이너가 8080에서 서비스를 제공하고 싶다면 이미지에 미리 httpd.conf의 내용중 Listen 80을 8080으로 바꾸어놓자 (sed 명령어 쓰기)

 

ADD와 COPY의 가장 큰 차이점

COPY는 패키지 파일을 붙여넣기하면 파일 자체가 그대로 붙여넣기 된다.

하지만 ADD는 패키지의 내용이 풀리면서 붙여넣기 된다.

 

git으로 먼저 파일을 받아오자

https://github.com/BuckyMaler/global.git

 

GitHub - BuckyMaler/global: HTML5 website template

HTML5 website template. Contribute to BuckyMaler/global development by creating an account on GitHub.

github.com

이걸 가지고 

```

tar cf global.tar global/*

파일 내용 수정

docker build -t global:1.0 .

docker run -d -p 8001:80 global:1.0

```

 

FROM centos:7
RUN yum update -y
RUN yum install httpd -y
ADD index.html /var/www/html/index.html
ADD global.tar /var/www/html/
EXPOSE 80 8080
CMD httpd -D FOREGROUND

잘 들어가진다.

 

5.2 Dockerfile 명령어와 데몬

 

명령실행(RUN)

컨테이너에는 FROM 명령에서 지정한 베이스 이미지에 대해 애플리케이션/미들웨어 등을 설치하거나 환경 구축을 위한 명령을 실행하기 위하여 RUN을 사용한다.

Dockerfile에서 RUN 은 Shell 형식과 Exec 형식으로 명령을 작성할 수 있다. Shell 형식으로 작성

 

두가지 방법이 존재한다.

Shell 방식은 명령어를 그냥 쓰면 되기 때문에 편리하다.

 

데몬실행(CMD)

RUN 명령은 이미지를 작성하기 위해 실행하는 명령을 기술하지만, 이미지를 바탕으로 생성 된 컨테이너 안에서 명령을 실행하려면 CMD 명령을 사용한다.

Dockerfile 내에서 CMD는 한번만 기술할 수 있으며 만약 여러번 기술 되었다면 마지막 CMD 만 유효하게 된다.

 

 

데몬실행(ENTRYPOINT)

ENTRYPOINT 명령에서 지정한 명령은 Dockerfile에서 빌드한 이미지로부터 Docker 컨테이너를 시작하기 때문에 docker container run 명령을 실행했을 때 실행된다.

CMD 명령은 컨 테이너 시작 시에 실행하고 싶은 명령을 지정해도 docker container run 명령 실행 시에 인수로 새로운 명령을 지정한 경우 이것을 우선 실행한다.

ENTRYPOINT는 명령에서 지정한 명령은 반드시 컨테이너에서 실행되는데, 실행 시에 명령 인수를 지정하고 싶을 때는 CMD 명령과 조합하여 사용한다

 

예를들어 상태확인 명령어 top을 쓰는데

그냥 배포하면 10초마다 갱신된다.

하지만 -d 옵션을 넣어주면 2초마다 갱신된다.

 

즉 ENTRYPOINT는 무조건 실행된다.

CMD는 container run 옵션과 겹치면 안쓴다는 것이다.

 

CMD나 ENTRYPOINT는 도커파일 내에서 한번만 사용할 수 있으므로 컨테이너 실행시 여러 명령을 실행하고자 한다면 다음과 같은 방법 사용하기

```

ADD ./a.sh /root

ENTRYPOINT ./root/a.sh

 

ENTRYPOINT /bin/bash /root/a.sh

ENTRYPOINT ["/bin/bash", "/root/a.sh"]

```

 

 

 

위와같이 testdev에는 Dockerfile만 만들어 놓고

그 안의 내용에 tar 파일이 필요하다는 정보도 함께 넣어놓는다.

 

팀원 : global 이라는 디렉토리 아래에 필요한 코드, 이미지 등을 모두 넣어두고 이를 global.tar로 만든다.

 

팀원의 Dockerfile은 어떤 이미지를 사용할지에 대한 정보만 넣어놓고 컨테이너를 만든다.

 

 

 

빌드 완료 후에 실행되는명령(ONBUILD)

ONBUILD 는 그 다음 빌드에서 실행할 명령을 이미지 안에 설정하기 위한 명령이다. 예를 들어 Dockerfile 에 ONBUILD 명령을 사용하여 어떤 명령을 실행하도록 설정하여 빌드하고 이미지를 작성한 뒤 해당 이미지를 다른 Dockerfile에서 베이스 이미지로 설정하면 빌드 했을 때 ONBUILD 명령에서 지정한 명령을 실행 시킬 수 있다

 

ONBUILD는 팀장이 베이스이미지를 만들고 이를 배포

개발팀은 팀장이 만든 베이스 이미지를 가져다가 새로운 이미지로 만들떄 동작하는 기능이다.

 

```

mkdir teamdev

cd teamdev

vi Dockerfile

```

하고 위와같이 dockerfile을 만들자. 여기에서 우리는 단 한번도 global.tar 파일을 만든적이 없다.

 

```

docker build -t web:1.0 .

```

이제 팀1이 되어서 dockerfile을 만들자 만드는 디렉토리에 반드시 global.tar 파일이 있어야 한다.

 

 

```

docker container run -d -p 8008:80 web:gildong

```

정상 실행된다.

 

컨테이너의 헬스 체크(HEALTHCHECK)

컨테이너 안의 프로세스가 정상적으로 작동하고 있는지를 체크하고 싶을 때에 사용한다. 일반적인 명령의 구문은 다음과 같다

 

실행을 했음에도 이미지를 잘못만들었다면 그냥 죽는다.

그래서 살아있는지 확인하는 것이다.

 

잘쓰는지는 모르겠다.

 

 

환경변수 설정(ENV) : 많이쓴다

Dockerfile 안에서 환경변수를 설정하고 싶을 때는 ENV 명령을 사용하며 다음 두 서식 중 하나로 기술할 수 있다.

모든 이미지의 환경변수 값이 같아진다.

 

 

작업디렉토리 지정(WORKDIR)

Dockerfile에서 정의한 명령을 실행하기 위한 작업용 디렉토리를 지정하고자 할 때 사용하 며 다음과 같은 명령을 실행하기 위하여 지정이 가능하다.

 

```

WORKDIR /test

RUN touch a.txt

RUN touch b.txt

RUN touch c.txt

#이 작업들은 test 폴더 아래에서 이루어진다.

 

RUN cd /etc && \  # 작업 디렉토리가 이동하지는 않는다.

touch d.txt  # 얘는 test에서 이루어진다. 

 

WORKDIR /etc

# 이후의 모든 작업은 /etc 아래에서 진행됨

```

 

만약 폴더가 없다면 만들어서 해준다.

 

 

사용자 지정(USER)

이미지 실행이나 Dockerfile 의 다음과 같은 명령을 실행하기 위한 사용자를 지정할 때 사 용한다

USER test 아래부터는 test 계정이 작업

 

라벨 지정(LABEL)

이미지에 버전 정보나 작성자 정보, 코멘트 등과 같은 정보를 제공할 때에는 LABEL 명령을 사용한다.

예전 MAINTAINER이다.

 

 

포트 설정(EXPOSE)

컨테이너의 공개 포트번호 지정할 때 사용 예를 들어 8080 포트를 공개하고자 한다면 다음과 같이 작성한다.

 

Dockerfile 내에서의 변수 설정(ARG)

Dockerfile 안에서 사용할 변수를 정의할 때에는 ARG 명령을 사용한다. ARG 명령을 사용하 면 변수의 값에 따라 생성되는 이미지의 내용을 바꿀 수 있다. ENV 와 달리 이 변수는 Dockerfile 안에서만 사용할 수 있다.

 

ENV는 컨테이너에서 사용하는 변수를 의미한다면

ARG는 도커파일 안에서 사용할 변수를 정의한다.

 

 

기본 쉘 지정(SHELL)

쉘 형식으로 명령을 실행할 때 기본쉘을 설정하려면 SHELL을 사용한다. SHELL을 지정하지 않으면 리눅스는 [“/bin/sh", "-c"], 윈도우는 [”cmd", "/S", "/C"] 가 기본이 된다

 

 

파일 및 디렉토리 추가(ADD)

이미지에 호스트상의 파일이나 디렉토리를 추가할 때에는 ADD 명령을 사용한다. ADD 명령은 다음과 같은 형식으로 작성이 가능하다. 원격지에 있는 파일도 붙여넣을 수 있고/tar 파일 풀면서 붙여넣을 수 있고/패턴도 사용가능하다

파일 복사(COPY)

이미지에 호스트상의 파일이나 디렉토리를 복사할 때에는 COPY를 사용한다. ADD 명령과 사실상 거의 동일하지만 ADD 명령은 원격파일의 다운로드나 아카이브 압축해 제 등과 같은 기능을 갖고 있지만, COPY 명령은 호스트상의 파일을 이미지 안으로 ‘복사’하 는 처리만 한다. 따라서 단순히 이미지 내에 파일을 배치하고자 할 때에는 COPY를 사용한 다

 

볼륨 마운트(VOLUME)

이미지에 볼륨을 할당하고자 할 때 사용한다. VOLUME ["/마운트포인트“] 와 같은 형식으로 구성하면 호스트나 다른 컨테이너에서 마운트 를 수행한다. 구성하는 형식은 다음과 같다.

 

볼륨 마운트하기

FROM centos:7
RUN yum -y install httpd
EXPOSE 80
VOLUME /etc/httpd
CMD httpd -D FOREGROUND

 

docker의 볼륨이 생긴것을 확인할 수 있다.

 

docker container inspect로 자세한 정보를 확인해보자

 

실재 경로로 가보니 무언가가 보인다.

 

더 자세히가보니 위와같이 httpd.conf가 있다.

 

그래서

컨테이너는 휘방성이고 컨테이너 내에서 이루어지는 작업(파일/디렉토리 만들기, 패키지 설치하기 등)은 컨테이너가 삭제된다면 모든 작업이 삭제되는 것이다. 만약 중요한 데이터가 컨테이너 내에 있었는데 컨테이너가 삭제되었다면... 해당 데이터도 함께 삭제되는 문제가 있을 수 있다. 이를 위해 컨테이너의 특정 디렉토리를 volume과 연결하게 되면 로컬 또는 원격지의 볼륨과 마운트 되어 해당 파일, 디렉토리등을 영구적으로 보관할 수 있게된다.

 

/etc/httpd 디렉토리는 실재로는 local storage와 연결되어 있다. 그럼 이 안의 파일들은 storage에서 볼 수 있다.

그래서 위에서 보이는 httpd.conf 파일을 수정해서 container의 수정을 바꾸어버릴 수도 있다.

 

Quiz.

베이스 이미지 mariadb:10.4 를 이용하여 아래의 조건에 맞는 컨테이너를 배포하고 ubuntu에서 직접 접속해 보세요.

 

root 패스워드 : test123

기본 database 이름 : testdatabase

기본 포트 : 3306, 하지만 외부에서 접속할 떄에는 33062와 같은 포트를 사용하여 접속한다.

mysql(mariadb)의 데이터는 로컬의 볼륨과 연결하여 혹시 컨테이너가 삭제되더라도 해당 데이터는 영구적으로 보관할 수 있어야 한다.

 

최종적으로 우분트에서 아래와 같이 접속

mysql testdatabase -u root -ptest123 -h 211.183.3.200 -P 33062

 

고민해야 할 사항)

mariadb에서 데이터는 어느 디렉토리에 위치하는가? -> volume과 연결하기 위해서 필요.

최종적으로 mariadb를 실행할 때에는 CMD ["mysqld"]

 

docker - Unable to build a mariaDB base in a Dockerfile - Stack Overflow

728x90