[Docker] 기초

최동혁·2023년 4월 17일
1

docker

목록 보기
1/5

개념

  • 도커는 vm ware 프로그램과 가장 비슷하다.

  • vm ware는 가상 머신을 생성해줬다.

  • 도커도 마찬가지로 가상머신을 생성하는건데 정확히 얘기하자면 가상머신이 아닌 컨테이너라고 한다.

  • vm ware 같은 하이퍼 바이저 프로그램이 만들어주는 가상머신이랑 도커가 만들어주는 컨테이너를 구분지을 수 있어야 한다.

  • 리눅스에 기본적으로 컨테이너라는 기능이 있었다.

  • 개발자나 엔지니어들이 이렇게 까지 쓸 수 있나 라는 걸 잘 몰라서 잘 안쓰는 기능이였다.

  • docker는 이걸 활용을 잘 해서 많이 쓰게 됨.

  • 많은 서버들을 사용해서 3 티어 구성을 했었다.

    • 서버 부하를 줄이기 위해서

    • 안정성 때문에

    • 하나의 컴퓨터에 다 구성해놓으면 하나의 컴퓨터가 털리면 가장 중요한 db가 털려버림.

    • 각 컴퓨터로 3계층을 나누었는데, 이런 경우 서버 확장을 위해 컴퓨터를 더 늘리다 보면 운영체제를 계속해서 더 깔아줘야함.

    • 각 컴퓨터마다 운영체제 메모리가 낭비되고 있음.

    • 하나의 컴퓨터는 운영체제 하나 공유해서 사용해서 메모리를 덜 낭비함.

    • 격리는 시켜야 되는데, 운영체제 낭비는 또 싫다.

    • 그렇기 때문에 컨테이너를 사용함.

    • 하나의 좋은 컴퓨터에 격리된 환경을 만들어준다.

    • vm ware 같은 경우 window 운영체제가 있다면, 그 위에 vm ware를 두고 그 위에 각 가상 환경을 생성했다.

    • 그런데 이런 가상 환경을 만들어도 각 운영체제를 설치해야 했다.

    • docker는 각자 격리된 환경에서 하나의 운영체제를 공유해서 사용함.

    • docker는 linux의 컨테이너 기능을 사용하는 것임.

    • 더 자세히 말하자면 운영체제 위에 docker engine이 있고 그것이 컨테이너들을 생성해주는 것이다. vm ware와 비슷하면서 다르다.

    • 컨테이너는 윈도우에서 만들 수 없다.

    • 그렇기 때문에 윈도우 컨테이너를 만들 수 없다.

    • 완전한 격리를 시키기 위해서, 완전한 docker를 만들기 위해서는 linux 상에서 메모리 격리, mount 격리, uts, ipc, 네트워크 등등 전부 수동으로 해줘야 한다.

    • 하지만 docker 명령어를 입력하면 이러한 과정들을 전부 자동으로 해준다!

사용 방법

설치

centOS

yum install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum-config-manager --enable docker-ce-nightly
yum-config-manager --enable docker-ce-test
yum install -y docker-ce docker-ce-cli containerd.io --allowerasing
systemctl restart docker
systemctl enable docker

nginx

  • docker pull nginx
  • 해당 명령어를 이용하면 nginx 이미지를 다운받는다.
    • nginx에 필요한, 컨테이너 상에 필요한 프로그램들을 다 모아놓아 압축파일 처럼 압축해(패키징) 사람들이 공유해서 사용하는 걸 이미지라고 한다.
    • 다운받고, 새로운 디렉토리를 만들고, chroot 명령어를 이용해 해당 디렉토리를 격리 시킨 후, 다운 받은 폴더들을 전부 옮겨서 넣어준다.
      • mkdir /nginx
      • chroot /nginx /bin/bash
      • 이게 nginx 폴더를 root 디렉토리로 bash를 실행시킨다는 의미
      • 물론 여기서 환경 변수 편집도 해줘야 nginx docker 이미지에 설치되어 있는 linux 프로그램 명령어를 사용할 수 있다.

특징

  • linux에서 사용하던 명령어는 전부 프로그램이다.
  • 격리를 시키면 환경 변수를 바꾸지 않는 한 명령어들이 잘 실행이 되지 않는다.
  • 특정 프로그램을 실행시키기 위해 필요한 프로그램들만 패키징해놨기 때문에 환경 변수를 잘 편집해 놓아도 linux에서 사용하던 명령어가 안 먹는게 있을 수 있다.
  • 예를 들어 ubuntu에서는 apt-get, centos에서는 yum 명령어를 이용해 라이브러리를 설치했는데, nginx 이미지에는 서버를 돌리기 위해 yum이나 apt-get 명령어가 필요가 없기 때문에 사용을 못한다.
  • 그러니깐 컨테이너는 특정 프로그램을 돌리기 위해 필요한 프로그램들을 전부 설치 해놓고 패키징해서 올려놓은 것이기 때문에 설치하는 명령어가 따로 필요가 없다.
  • 또한 컨테이너는 실행되면서 생긴 파일들 같은 경우 메모리 상에 저장되어 있다가 컨테이너가 꺼지면 메모리가 날라가기 때문에 파일들도 날라간다.
  • 그렇기 때문에 db 같은 경우 컨테이너로 사용하지 않는다.
    • 무슨 이유에서 db 컨테이너가 꺼지는 경우 저장된 데이터가 다 날라가기 때문에.
  • 그런데 카카오는 db를 컨테이너로 올렸다.
    • 쿠버네티스여서 가능한데, 이건 나중에 따로 얘기할것.
  • 그리고 가상 머신과 비교해서 빠르다.
    • 가상 머신은 전부 파일로 저장된다.(하드디스크)
    • 컨테이너는 메모리에 저장된다.
  • 가상 머신은 운영체제를 설치해야 하지만, 컨테이너는 Host PC 운영체제를 사용함.
    • 가상 머신을 하나 더 늘리기 위해 이미지를 복사하거나 운영체제를 설치해야 하는데, 컨테이너는 그런 시간 절약 가능
    • 구글에서 1주일에 배포하는 어플리케이션은 약 20억개이다.
    • 이걸 가상 머신으로 하면 시간이 말도 안되게 많이 든다.
    • 그렇기에 컨테이너를 사용
    • 이런 20억개의 컨테이너를 1주일마다 계속 관리를 해야하는데, docker로만 관리하기 힘듬.
    • 그렇기에 만든 프로그램이 쿠버네티스.
    • 쿠버네티스는 이런 docker로 만든 컨테이너들을 관리하는 프로그램이다.

결론

  • 리눅스에서 chroot라는 명령어를 이용해 컨테이너를 만들어 격리 시킬 수 있음.
  • 그런데 격리만 시키면 linux 명령어를 사용하기 위한 프로그램이나, 메모리 관련 격리, 네트워크 등등 격리시킬게 한두개가 아님.
  • 여기서 격리는 자신이 실제 독립된 가상 컴퓨터로 켜졌다고 생각하는 것.
  • 그런걸 전부 자동화 해준 것이 docker임.
  • 또 거기서 docker hub 같은 곳에 여러 이미지들이 올라와 있음.
  • nginx 같은 경우를 예시로 들면 docker pull nginx를 이용해 docker hub에 있는 파일을 받아오면 nginx를 돌리기 위해 필요한 프로그램들과 필요한 명령어 프로그램들을 패키징 해놓은 것임.
  • 다운 받아 chroot 명령어를 이용해 격리 시키고, 환경 변수 편집만 해주면 됨.
  • 컨테이너는 운영체제를 host pc의 운영체제로 공유해서 돌림.
  • 그렇기에 새로운 컨테이너를 만들기 위해 운영체제를 다시 설치할 필요 없음.
  • 그리고 컨테이너는 가상 머신과 다르게 새로 생성되는 프로그램이나 파일들을 하드디스크에서 불러오는게 아닌 메모리에서 불러옴
  • 그렇기에 휘발성임. 컨테이너가 꺼지면 이미지에 패키징된 파일들을 제외하고 전부 날라감.
  • 메모리에서 불러오기 때문에 hdd를 사용하는 가상 머신보다 빠름.
  • 구글에서는 매주 20억개의 애플리케이션이 배포됨.
    • 여기서 말하는 배포는 nginx 같은 서버에 올리는 것.
  • 컨테이너의 이런 장점들 때문에 구글에서는 docker를 사용해서 컨테이너로 배포를 함.
  • 그런데 20억개의 컨테이너들을 docker로만 관리하기에는 어려움.
  • 그렇기에 만든 것이 쿠버네티스임.

명령어

docker run

  • 각종 옵션이나 내가 실행하고 싶은 컨테이너의 이미지를 뒤에다가 넣어주면 됨.
  • 컨테이너 이미지는 docker hub에 올라가있음. 거기 들어가서 찾아보면 됨.
  • 버전도 정확히 명시하고 싶다면 :뒤에 버전을 명시해주면 된다.
  • 만약 centos를 최신 버전으로 이미지를 가져오고 싶다면 docker run centos:latest 이런식으로 사용
  • 처음에는 local 컴퓨터에서 해당 이미지를 찾는다.
  • 없으면 docker hub에서 찾아서 다운로드 하고 실행한다.
  • 이걸 새로운 프롬프트에서 실행시키고 싶다면?
    • docker run -it centos:latest bash
    • 여기서 i는 bash에 연결해주는 거고, t는 해당 프로그램을 내 화면에 띄우겠다는 뜻.
    • 이러면 host pc와 격리된 환경에서 실행이 된다.
    • 이런 명령어를 사용해주면 알아서 환경변수도 잘 편집되어서 새로운 컨테이너에서 완전히 격리된 채로 실행이 자동으로 된다.
    • ctrl + d 명령어를 이용해 컨테이너를 빠져나갈 수 있다.
    • 이건 종료를 하고 빠져나가는 것인데, ctrl + p + q는 실행 해놓고 빠져나감.
  • docker run --name some-nginx -d nginx
    • --name은 만약 명시를 안해놓고 실행하면 랜덤한 이상한 이름이 나옴. 그래서 이름 명시해서 컨테이너 id 말고 이름으로 실행, 종료, 조작 가능.
    • -d는 백그라운드에서 실행시키겠다는 옵션
  • docker run --name some-nginx -p 9999:80 -d nginx
    • -p 옵션은 포트포워딩임.
    • 외부 사용자들이 내 host pc의 ip 9999 포트로 들어오면 내 사설 ip의 80번 포트로 연결하겠다는 소리.

docker ps

  • 현재 실행되고 있는 컨테이너를 확인할 수 있다.
  • docker ps -a
    • 실행했다가 종료된 컨테이너들도 확인할 수 있다.

docker rm

  • docker ps -a를 이용해 컨테이너 id를 알아낸다.
  • docker rm [컨테이너 ID]를 써주면 해당 컨테이너를 지울 수 있다.
    • 전부 다 안써도 됨. 대충 3개정도만 써줘도 해당되는 컨테이너 찾아서 지워줌.

docker create

  • 바로 실행시키지 않고 이미지만 생성하고 싶을 때 사용
  • docker create -it centos:latest
  • 생성하고, docker ps로 확인, docker ps -a로 확인해서 잘 생성되었고 실행이 안되고 있는지 확인
  • docker start [컨테이너 ID]
    • 생성한 컨테이너가 실행된다.

docker stop

  • docker stop [컨테이너 ID]
  • 해당 컨테이너 종료

docker attach

  • 생성한 컨테이너 안으로 들어가는 명령어
  • docker attach [컨테이너 ID]

docker exec

  • docker exec [컨테이너 ID]

정리

실행

  • docker run -it 이미지 bash
  • 혹은
  • docker create 이미지
  • docker start ID
  • docker attach ID

종료

  • docker stop ID 컨테이너 종료
  • 혹은
  • Ctrl + d 컨테이너 종료
  • 혹은
  • Ctrl + p + q 종료 하지 않고 컨테이너 빠져나가기

컨테이너 개발

베이스 이미지

  • 컨테이너를 개발할 때 기본이 되는 이미지를 베이스 이미지라고 한다.
  • 도커 허브에 다양한 베이스 이미지들이 등록되어 있다.
  • 리눅스 배포판 : ubuntu, centos, debian, fedora, amazonlinux 등
  • 프로그래밍 언어 : node, golang, php, pythom, openjdk, java 등
  • NoSQL DB : redis, mongo, memcached 등
  • SQL DB : postgres, mysql, mariadb 등
  • Web 서버 : nginx, httpd 등
  • 서블릿/JSP 서버 : tomcat, jetty 등
  • 콘텐츠 관리 시스템 : wordpress, ghost 등
  • 컨테이너 : docker, swarm 등
  • CD/CI : maven, jenkins 등
  • 로그와 메트릭 분석 : ElasticSearch, Logstach, Kibana 등

컨테이너 개발 순서

  1. 디렉토리를 준비, 이미지에 포함시킬 파일들을 모은다.
  2. Dockerfile 작성
  3. 컨테이너에서 실행할 애플리케이션 코드를 작성하고 유닛 테스트 실행
  4. 이미지 빌드
  5. 컨테이너를 실행하여 동작을 확인

도커 파일

  • 도커 파일은 컨테이너를 만들고 해야하는 일련의 작업들을 미리 선언함으로써 매번 해당 작업을 하지않고도, 컨테이너 생성시 자동으로 등록된 작업이 실행된 후 컨테이너를 생성할 수 있는 파일

  • 매뉴얼 작업을 기록한 Dockerfile 생성 (파일의 이름이 Dockerfile)

  • 빌드 명령어가 Dockerfile 을 읽어 이미지를 생성

FROM  alpine:latest				# FROM 베이스 이미지 지정
RUN   apk update && apk add figlet		# RUN 컨테이너에서 실행할 명령어 지정
ADD   ./message /message			# ADD 컨테이너에 추가할 파일, 현재 디렉토리의 message 파일을 컨테이너의 / 디렉토리에 배치
CMD   cat /message | figlet			# CMD 컨테이너가 실행 된 후 실행할 명령어 지정
  • 그 밖에 많이 쓰는 커맨드
COPY [원본] [사본]			# 컨테이너 내 파일을 컨테이너의 다른 곳에 복사
ENV [변수]=[값]				# 환경 변수 설정
EXPOSE [포트]				# 공개 포트 설정
WORKDIR [경로]				# 컨테이너 내에서 작업 디렉토리 지정, cd 같은 것
MAINTAINER [이름]				# 이미지에 대한 작성자 추가

이미지 빌드

  • docker build --tag hello:1.0 [도커파일 경로]

실행 및 확인

  • docker images
  • docker run hello:1.0

실습

Dockerfile 생성

FROM	alpine:latest
RUN 	apk update && apk add figlet
ADD 	./message /message
CMD	cat /message | figlet

이미지 생성

  • docker build --tag message:1.0 .
  • 지금 현재 이 디렉토리 안에 있는 것들을 message라는 이름의 이미지로 tag는 1.0으로 만든다는 얘기

  • docker images 명령어를 이용해 이미지가 잘 만들어졌는지 확인

만든 이미지로 컨테이너 생성

  • docker run message:1.0

  • 이렇게 하면 dockerfile에 있는 명령어들을 자동화해서 결과물을 보여준다.

3계층

DB 구성

  • docker run --name my-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=qwer1234 -d mysql:5.7.41

  • 서버가 잘 실행됐는지 확인
  • workbanch로 잘 들어가진다.

DB 생성

CREATE DATABASE web;
use web;
CREATE TABLE student (sname VARCHAR(10), sage INT);
INSERT INTO student VALUES('kim',10);
INSERT INTO student VALUES('lee',20);
INSERT INTO student VALUES('park',30);
INSERT INTO student VALUES('sim',40);

WAS 구성

Dockerfile

  • vi Dockerfile
FROM tomcat:9.0.73-jdk8-corretto-al2
RUN rm -rf /usr/local/tomcat/conf/server.xml
ADD ./server.xml /usr/local/tomcat/conf/server.xml
RUN mkdir /usr/local/tomcat/webapps/cdh
ADD ./db.jsp /usr/local/tomcat/webapps/cdh/db.jsp
ADD ./mysql-connector-java-8.0.19.jar /usr/local/tomcat/lib/
EXPOSE 8080
EXPOSE 8009
CMD catalina.sh run
  • server.xml 파일
  • db.jsp 파일
  • mysql-connector~~~ 파일
  • 3가지 파일이 필요하다.

server.xml

  • server.xml 파일은 직접 wget 명령어를 이용해 tomcat을 설치해서 위에 쓰인 경로에 가면 있다. cp 명령어를 이용해 docker를 실행할 디렉토리에 옮겨놓는다.
  • 153번줄
<Context path="" docBase="cdh" reloadable="true" />
  • 121번줄
<Connector protocol="AJP/1.3"

                    address="0.0.0.0"

                    secretRequired="false"

                    port="8009"

                    redirectPort="8443" />
  • docBase는 내가 cdh 폴더 밑에 db.jsp 파일을 만들것이기 때문에 cdh로 정했다.

    db.jsp

<%@page import="java.sql.*"%>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
        <%
                Connection conn = null;
                ResultSet rs = null;

                String url = "jdbc:mysql://200.200.200.10:3306/web?serverTimezone=UTC";
                String id = "root";
                String pwd = "qwer1234";


                try {
                        Class.forName("com.mysql.jdbc.Driver");
                        conn = DriverManager.getConnection(url, id, pwd);
                        Statement stmt = conn.createStatement();


                        String sql = "SELECT sname FROM student";
                        rs = stmt.executeQuery(sql);

                        while(rs.next()) {
                                out.println(rs.getString("sname"));
                        }


                        conn.close();
                } catch (Exception e) {

                        e.printStackTrace();
                }
        %>
</body>
</html>
  • 여기서 db 서버의 ip와 관리자 계정, 비밀번호를 잘 설정해줘야 한다.
  • 위의 코드는 db가 잘 연결되었는지, db 데이터를 잘 불러오는지 보기 위한 jsp 파일이다.

mysql-connector

이미지 생성

  • docker build --tag mytomcat:1.0 .

이미지 실행

  • docker run -p 8080:8080 -d mytomcat:1.0

결과

  • 나는 cdh 폴더에 db.jsp 파일에 db 연동 결과물을 출력하게 해주었다.
  • 그렇기에 8080포트에 접속해 /cdh/db.jsp로 접근하면 나와야 한다.

  • 잘 된다.

WS 구성

Dockerfile

FROM httpd:latest
ADD ./mod_jk.so /usr/local/apache2/modules/mod_jk.so
ADD ./workers.properties /usr/local/apache2/workers.properties
RUN rm -rf /usr/local/apache2/conf/httpd.conf
ADD ./httpd.conf /usr/local/apache2/conf/httpd.conf
EXPOSE 80
CMD httpd-foreground

mod_jk.so

  • yum install httpd httpd-devel gcc gcc-c++

  • wget https://dlcdn.apache.org/tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.48-src.tar.gz

  • tar zxvf tomcat-connectors-1.2.48-src.tar.gz

  • cd tomcat-connectors-1.2.48-src/native/

  • ./configure --with-apxs=/usr/bin/apxs

  • yum install -y make

  • yum install -y redhat-rpm-config

  • make

  • 위의 모듈들을 설치하고 실행하면, tomcat-connectors-1.2.48-src/native/apache-2.0 밑에 mod_jk.so 생성됨

  • 해당 파일을 docker를 실행할 디렉토리에 복사

workers.properties

worker.list=worker1

worker.worker1.type=ajp13
worker.worker1.host=200.200.200.10
worker.worker1.port=8009

httpd.conf

  • 위의 dockerfile에서 ADD ./workers.properties /usr/local/apache2/workers.properties 까지만 실행시키고, httpd.conf를 삭제하는 명령어는 잠시 실행 안되게 지워놓고 이미지 생성.
  • 그 후, 컨테이너에 들어가서 /usr/local/apache2/conf/httpd.conf 경로에 있는 httpd.conf 복사 후, 원래 bash로 나와서 컨테이너를 실행시킬 디렉토리에 붙여넣기
  • 그리고 마지막 줄에 밑에 코드 추가
LoadModule jk_module /usr/local/apache2/modules/mod_jk.so

<IfModule jk_module>
	JkWorkersFile /usr/local/apache2/workers.properties
	JkLogFile /usr/local/apache2/logs/mod_jk.log
	JkLogLevel info
	JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"
	JkMount /*.jsp worker1
</IfModule>

이미지 생성

  • docker build --tag myapache:1.0 .

이미지 실행

  • docker run -p 80:80 -p 8009:8009 -d myapache:1.0

결과

  • 80번 포트로 접속해서 db.jsp 경로에 접속했을 때 나오면 성공
profile
항상 성장하는 개발자 최동혁입니다.

0개의 댓글