VM을 Docker로 구현

2020. 11. 23. 16:47

Docker는 가상화가 아니다!

처음에는 Docker에 Ubuntu나 CentOS를 설치해 사용했다.
사용하려는 목적이 Synology NAS에서 apt 패키지 매니저를 사용하기 위한 목적이었고, 쉘 사용이 쉬워서 OS 컨테이너를 사용했다.
그러니까... 가상화의 목적으로 사용했다는 것이다.

그러나 systemctl이나 네트워크 구성이 어려운 점, Docker의 목적과 달리 백업, 배포가 어려운 점 때문에 Docker에 OS를 돌리는 건 그만 두기로 했다.
그래서 아래와 같은 방법으로는 docker를 사용하지 않을 건데, 혹시 나중에라도 필요하게 될까봐 기록으로 남겨본다.

아래 방법을 따라하면 CentOS 이미지를 사용하여 Docker를 구성하고, systemctl을 사용할 수 있고, 고유의 IP를 부여할 수 있다.

VM을 Docker로 구현하려 함

VM

  • 모든 컴퓨터 하드웨어를 가상화하고 OS를 실행 함. 약 30% 성능 저하가 있음.
  • 최근에는 Hypervisor를 사용하여 CPU가상화를 하지 않아 성능 저하가 낮은 편. 하지만 기타 IO장치들은 가상화를 하기 때문에 IOPS가 낮음. (최대 50% 저하)
  • OS 설치해야 함. 메모리 및 디스크 관리를 호스트 OS와 가상 OS에서 동시에 수행하며, 가상 OS에 할당한 메모리는 호스트에서 사용할 수 없음.

Docker

Docker의 원래 목적은 OS 자체를 가상화하는 것이 아니고 프로그램별로 containerize(컨테이너화) 하는 것이다.

  • 운영체제를 설치하지 않고, 서비스에 필요한 패키지만 설치하고 설정파일을 import 하여 컨테이너로 만드는 방식이다.
  • OS가 없기 때문에 메모리, 디스크 관리를 호스트 OS에서만 관여하므로 오버헤드가 적다.
  • 단점은 OS가 없기 때문에 ssh같은 원격 접속 도구나 yum 같은 패키지 매니저가 없다는 것이다.
  • 같은 환경의 컨테이너를 몇 줄의 텍스트로 만들 수 있으며, 따라서 배포가 쉽다. 이런 방식 덕분에 낯선 방식이지만 서버 유지/보수는 더 쉽다.
  • docker의 목적상 호스트 컴퓨터의 환경을 따르기 때문에 기존의 가상머신처럼 개별적 IP를 부여하기 어렵다.
Docker로 환경을 구축하는 두 가지 방법
  1. OS 자체를 컨테이너에 구현하는 방법이다. 개별적인 IP를 부여하고자 할 때는 그 과정이 복잡하다. 지금까지는 이 방법으로 블로그를 운영했다.
    그리고 이 방법으로 컨테이너를 만드는 방법을 오늘 소개하려고 한다.
  2. Docker의 원래 목적대로 각 애플리케이션 별로 컨테이너를 만든다. 별도의 IP는 부여하지 않으며, 새로 구성할 때는 컨테이너를 새로 만들어야 한다.
    이 방식이 원래 Docker의 용도대로 이용하는 방법이다.
    2번 방법은 구축/유지 보수가 쉬운 장점이 있지만 낯선 방식 때문에 Docker에 익숙한 관리자가 필요하다.

Docker 설치

Docker repo 추가 및 설치

yum install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install docker-ce docker-ce-cli containerd.io

systemctl enable docker

docker 볼륨 위치 이동, docker 네트워크에 dns 정보 강제 지정

nano /etc/docker/daemon.json
{
    "data-root": "/mnt/RAID-Storage/docker/",
    "dns": ["192.168.0.1"]
}

Docker에서 디스크 크기 제한을 가능하도록 변경

RAID-Storage에 quota 마운트 옵션 지정

nano /etc/fstab

UUID=...... /mnt/RAID-Storage xfs defaults,prjquota 0 1

원래 defaults인 부분을 defaults,prjquota로 변경한다.
이러면 xfs자체에서 quota 기능을 구현하고, docker는 xfs의 기능을 사용한다.

이후 컨테이너를 만들 때 --storage-opt size=120G 옵션 사용.

고유 IP 할당

고유 IP를 할당하기 위해 Linux 커널에서 기본으로 제공하는 가상 네트워크 어댑터를 활성화한다.

서버 부팅시에 macvlan을 자동으로 구성하는 스크립트.
cd /etc/sysconfig/network-scripts
wget https://raw.githubusercontent.com/larsks/initscripts-macvlan/master/ifdown-macvlan
wget https://raw.githubusercontent.com/larsks/initscripts-macvlan/master/ifup-macvlan
chmod +x ifup-macvlan ifdown-macvlan
macvlan 구성
nano /etc/sysconfig/network-scripts/ifcfg-macvlan

DEVICE="macvlan"
TYPE=macvlan
DEVICETYPE=macvlan
MODE=bridge
MACVLAN_MODE=bridge
PHYSDEV=br0
MACVLAN_PARENT=br0
BOOTPROTO=static
IPADDR=192.168.0.170
NETMASK=255.255.255.0
GATEWAY=192.168.0.1
NM_CONTROLLED=no
ONBOOT=yes
Docker에서 macvlan 네트워크 생성
docker network create -d macvlan \
    --subnet=192.168.0.170/24 \
    --gateway=192.168.0.1 \
    -o parent=br0 \
    -o macvlan_mode=bridge \
    macvlan

이 후 컨테이너를 생성할 때 --network macvlan 옵션, --ip 192.168.0.XXX 옵션을 사용하고
각 컨테이너마다 docker exec -it "컨테이너 이름" "echo 'nameserver 192.168.0.1' >> /etc/resolv.conf" 를 수행해야 한다.

systemctl (서비스 관리 도구) 사용

docker는 기본적으로 systemctl을 사용할 수 없다. OS를 가상화하는 목적이 아니기 때문이다.
systemctl을 사용하기 위해서는 systemctl에 필요한 파일을 만들어야 한다.

빈 디렉토리에 Dockerfile 만들고 이미지 빌드
mkdir docker && cd docker
nano Dockerfile
FROM centos:7
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in ; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/;\
rm -f /etc/systemd/system/.wants/;\
rm -f /lib/systemd/system/local-fs.target.wants/; \
rm -f /lib/systemd/system/sockets.target.wants/udev; \
rm -f /lib/systemd/system/sockets.target.wants/initctl; \
rm -f /lib/systemd/system/basic.target.wants/;\
rm -f /lib/systemd/system/anaconda.target.wants/*;

# 언어셋 설치
RUN yum clean all \
&& yum repolist \
&& yum -y update \
&& sed -i "s/en_US/all/" /etc/yum.conf \
&& yum -y reinstall glibc-common

# epel-release 활성화
RUN yum install epel-release -y

# 기본적으로 필요한 OS 패키지를 설치한다.
RUN yum -y install tar unzip vi vim telnet net-tools iproute curl openssl \
apr apr-util apr-devel apr-util-devel nano firewalld git \
elinks locate python-setuptools

# ssh 서버 설치
RUN yum -y install openssh-server \
&& echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config \
&& echo 'PasswordAuthentication no' >> /etc/ssh/sshd_config \
&& mkdir /root/.ssh && echo 'ssh-rsa "키" kollhong@localhost.localdomain' >> /root/.ssh/authorized_keys\
&& yum clean all

RUN systemctl enable sshd

# 타임존 변경
ENV LANG=ko_KR.utf8 TZ=Asia/Seoul

# 컨테이너 실행시 실행될 명령
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]

Dockerfile에 기반하여 컨테이너 이미지 생성

docker build --rm -t local/centos7 .

컨테이너 만들기

이제 docker run 명령어로 컨테이너를 만들어서 가상머신처럼 사용할 수 있다.

컨테이너를 만들 때 local/centos7 이미지로 container를 만들면 systemctl을 사용할 수 있다.

docker run --memory "2g" --storage-opt size=120G -v /sys/fs/cgroup:/sys/fs/cgroup:ro -v "디스크 디렉토리":"컨테이너 마운트 위치" --privileged --network macvlan --restart always --ip "컨테이너 IP" --dns 192.168.0.1 -t -d --name "컨테이너 이름" local/centos7

-v 옵션은 호스트 컴퓨터의 볼륨을 컨테이너에 마운트한다.

systemctl을 사용하기 위해서는 아래 옵션이 필수적이다.
-v /sys/fs/cgroup:/sys/fs/cgroup:ro : 이 옵션은 systemctl을 사용하는데 필요한 컨트롤 그룹 정보를 컨테이너에서 확인할 수 있게 한다.
-t, -d : 이 옵션은 유사 TTY 환경을 구현하고, detatch 모드로 컨테이너를 실행한다.

예시

docker run --memory "2g" -v /sys/fs/cgroup:/sys/fs/cgroup:ro -v /mnt/RAID-Storage/docker_volumes/bio-processor/:/opt --privileged --network macvlan --restart always --ip 192.168.0.171 --dns 192.168.0.1 -t -d --name "bio-processor" local/centos7

컨테이너(게스트 컴퓨터) 접속

docker exec -it "컨테이너 이름" "명령"
명령은 보통 /bin/bash이다.

컨테이너 백업

현재 컨테이너를 image로 저장

docker commit "컨테이너 이름" "이미지 이름"

image를 tar로 내보내기

docker save -o "파일 이름.tar" "이미지 이름"

tar를 이미지로 불러오기

docker load -i "파일 이름.tar"

이미지 확인

docker image ls 명령을 사용해서 불러온 이미지가 있는지 확인

docker run... 명령을 사용할 때 이미지를 선택하여 컨테이너 생성할 수 있다.

+ Recent posts