앞에서는 docker commit을 통해 이미지를 작성했지만 스크립트를 통해서 도커 이미지를 생성할 수도 있다. httpd 도커 이미지를 사용해 Dockerfile을 통해 도커 이미지를 빌드해보자.
내가 지정한 디렉토리(여기서는 Dockerwork 이름의 폴더)를 생성하고 Dockerfile 라는 이름으로 파일을 생성한다. (뒤에 확장자가 붙으면 안된다. 확장자가 붙어 생성되면 확장자를 지워준다.)
FROM httpd
COPY ./webapp /usr/local/apache2/htdocs
CMD ["httpd-foreground"]
FROM httpd : httpd 도커 이미지를 기반으로 새로운 이미지를 생성한다.COPY ./webapp /usr/local/apache2/htdocs : 호스트 시스템의 ./webapp 디렉토리의 내용을 컨테이너 내부의 /usr/local/apache2/htdocs 디렉토리로 복사한다.CMD ["httpd-foreground"] : 이 명령어는 컨테이너가 시작될 때 실행할 기본 명령어를 정의한다. 여기서는 Apache HTTP Server를 foreground 모드로 실행하는 명령어인 httpd-foreground를 실행하도록 설정한다.httpd 는 /usr/local/apache2/htdocs 폴더의 index.html 파일을 띄우게 되어있다.
위에서 호스트 시스템(Docker를 실행하고 있는 환경)의 ./webapp 디렉토리의 내용을 /usr/local/apache2/htdocs 경로로 복사하도록 명령어를 만들었으므로 현재 경로(Dockerwork)에 webapp 폴더를 생성하고 index.html 파일을 생성하면 자동으로 컨테이너의 지정한 경로로 똑같은 파일들이 생긴다. (내용은 h1태그로 “Hello World!”를 입력했다.)
Dockerfile 이 존재하는 폴더로 이동하고 빌드 명령어를 실행한다.
$ docker build -t webserver ./
docker build : Docker 이미지를 빌드하는 명령어이다.-t webserver : -t 옵션은 빌드한 이미지에 태그를 부여한다. 여기서는 ‘webserver’라는 태그를 사용한다../ : 해당 경로의 Dockerfile 파일을 사용해서 이미지를 빌드한다.(”./”는 현재 경로를 의미한다)$ docker run -dit -p 8080:80 webserver
httpd 이미지를 이용해서 호스트 시스템의 webapp폴더에 있는 내용을 복사해 넣은 새로운 이미지가 생성되었다.
이 이미지를 docker run 명령어를 사용해서 컨테이너로 실행하고 8080포트로 접속해보면 만든 index.html파일의 내용이 보이는 것을 확인할 수 있다.
앞에서는 Dockerfile에 CMD 명령어로 실행시킬 명령어를 입력했다.
Entrypoint 명령어를 이용해서 무조건 실행시킬 명령어를 입력하고 CMD에는 옵션들을 입력하는 전략을 사용한다.
FROM openjdk:11-jdk-slim
WORKDIR /app
COPY build/aws-v3-0.0.3.jar ./application.jar
# 실행할 명령어 입력 (무조건 실행)
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=dev", "application.jar"]
# 옵션을 부여한다.
CMD ["--server.port=5000"]
FROM openjdk:11-jdk-slim : openjdk:11-jdk-slim 이미지를 사용해서 새로운 이미지를 생성하겠다는 명령어이다. (11-jdk-slim은 openjdk의 태그명이다.)WORKDIR /app : 생성한 서버에 처음으로 진입할 경로(작업할 디렉토리를 정한다)를 입력한다. 여기서는 /app 폴더로 이동한다.COPY build/aws-v3-0.0.3.jar ./application.jar : 호스트의 build/aws-v3-0.0.3.jar 파일을 WORKDIR로 지정한 컨테이너의 경로로 application.jar 이름으로 복사한다는 뜻이다. (즉 스프링 프로젝트를 빌드한 결과물 jar 파일을 복사한다.)ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=dev", "application.jar"] : ENTRYPOINT로 컨테이너가 시작될때 실행할 명령어를 정한다.CMD ["--server.port=5000"] : ENTRYPOINT 명령어에서 지정한 jar 파일이 실행될 때 옵션으로 전달한다. 포트번호를 5000으로 연다.$ docker build -t java-server .
docker build 명령어를 사용해서 현재 경로(” . ”)의 Dockerfile 이름의 파일을 찾아 실행시키고 결과물을 java-server 이름으로 생성한다.
빌드가 완료되면 docker images 로 이미지가 생성되었는지 확인한다.
$ docker run -dit 8080:5000 java-server
앞서 생성한 이미지를 컨테이너로 실행시킨다. CMD 명령어로 --server.port=5000 을 지정해 5000번 포트로 실행되게끔 했으므로 포트 포워딩은 5000포트로 설정한다.
Dockerfile을 이용하여 Nginx 서버를 만들고 원하는 페이지가 뜨도록 설정해보자.
FROM ubuntu
RUN apt-get update
RUN apt-get install -y nginx
WORKDIR /var/www/html
COPY ./webapp/index.html ./index/nginx-debian.html
# 포그라운드로 실행해야 한다.
ENTRYPOINT ["nginx", "-g", "daemon off;"]
FROM ubuntu : 우분투 이미지를 사용하여 이미지를 생성한다.RUN apt-get update : 컨테이너 내에서 실행할 명령어를 RUN 으로 입력한다.RUN apt-get install -y nginx : 컨테이너 내부에서 Nginx를 설치한다. -y 옵션을 사용해서 설치중 yes 로 대답해 끊기지 않게 한다.WORKDIR /var/www/html : 작업 디렉토리를 설정한다. 컨테이너 내부에서 최초 진입점을 설정한다.COPY {호스트의 파일 경로} {컨테이너 내부의 경로 및 저장할 파일명} : 호스트의 파일을 지정한 컨테이너 경로에 지정한 파일명으로 복사한다. 여기서는 현재 경로의 webapp폴더의 index.html 파일을 컨테이너의 작업 디렉토리 기준 index폴더에 nginx-debian.html 이름으로 복사한다.ENTRYPOINT ["nginx", "-g", "daemon off;"] : 앞서 배운 ENTRYPOINT로 실행할 명령어를 설정한다. nginx 서버는 포그라운드로 실행한다. 백그라운드로 실행할경우 바로 중지된다.현재 경로의 webapp 폴더에 index.html 파일을 생성해 원하는 디자인을 적용했다.
$ docker build -t nginx-server .
$ docker run -dit -p 8080:80 nginx-server
docker build -t nginx-server . 명령어를 수행하면 현재 경로의 Dockerfile 파일을 찾아 수행해 nginx-server 라는 이름으로 이미지가 빌드된다.
만든 nginx-server 컨테이너를 run 하고 8080 포트로 접속해보면 앞서 만든 index.html 파일이 뜨는 것을 볼 수 있다.
Nginx 서버를 만들고 안에서 설정파일이나 index.html 파일을 수정하고 싶어도 vim 이 기본적으로 설치되어 있지 않아 수정이 불가능하다. Dockerfile에 vim 설치 명령어를 입력해서 설치하고 수정하는 명령어까지 입력하면 복잡해진다.
따라서 호스트에서 미리 Nginx 설정파일과 에러페이지(50x.html), 메인페이지(index.html)를 생성해 COPY 명령어를 사용해 지정된 경로에 덮어 씌우면 이 문제를 해결할 수 있다.
/etc/nginx/conf.d 경로에 설정파일인 default.conf 파일로 존재한다./usr/share/nginx/html 경로에 각각 50x.html, index.html 파일로 존재한다.따라서 우리는 각각의 경로에 우리가 직접 생성한 default.conf, 50x.html, index.html 파일을 COPY 명령어를 통해 복사해 덮어씌워주면 된다.
default.conf 파일의 내용이다. 사실상 기존의 주석만 제거했다.
최종적으로 만들어진 nginx 서버의 default.conf 파일과 비교해서 COPY가 제대로 됬는지 확인하기 위해서 제거했다.
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Welcome Nginx!!</h1>
</body>
</html>
h1 태그로 각 페이지를 구별할 수 있는 쉬운 문구를 작성했다.
FROM nginx
COPY webapp /usr/share/nginx/html
COPY conf/nginx.conf /etc/nginx/conf.d/default.conf
ENTRYPOINT ["nginx", "-g", "daemon off;"]
위에서 배웠던 명령어들을 사용하여 생성한 Dockerfile 이다.
Nginx 이미지를 바탕으로 생성할 것이고 호스트(나)의 webapp 폴더의 내용(50x.html, index.html)을 컨테이너의 /usr/share/nginx/html 폴더에 똑같이 복사 붙여넣기 한다. (메인페이지 적용)
호스트의 conf/nginx.conf 폴더의 내용을 컨테이너의 /etc/nginx/conf.d/default.conf 폴더로 똑같이 복사 붙여넣기 한다. (Nginx 설정파일 적용)
ENTRYPOINT로 컨테이너가 생성되고 실행되면 수행할 명령어를 작성한다. Nginx 서버를 포그라운드로 실행시킨다.
Nginx 설정을 사용하여 리버스 프록시를 설정해 클라이언트의 요청을 분산시켜보자.
분산시킬 2개의 서버를 생성하기 위해 각각 Dockerfile, index.html 파일을 준비한다.
FROM nginx
COPY webapp /usr/share/nginx/html
ENTRYPOINT ["nginx", "-g", "daemon off;"]
server1, server2 폴더를 생성하고 각각에 같은 내용의 Dockerfile 파일을 생성한다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Welcome Nginx Server1 !!</h1>
</body>
</html>
각 폴더에 webapp 폴더를 생성했고 안에 index.html 을 통해 현재 어떤 서버로 들어왔는지 알 수 있게 문구를 작성했다. (여기서는 server1에는 “Welcome Nginx Server1 !!”, server2에는 “Welcome Nginx Server2 !!” 문구를 작성했다.)
# server 1
$ docker build -t server1 ./server1
$ docker run -d -p 8081:80 server1
# server 2
$ docker build -t server2 ./server2
$ docker run -d -p 8082:80 server2
각각의 Dockerfile을 실행하여 2개의 서버를 생성하고 백그라운드로 실행시킨다.
server1은 8081, server2은 8082 포트로 포트 포워딩했다.
이제 각각의 서버로 연결시켜줄 단일 진입점인 로비 서버를 만들어보자. lb 이름의 폴더를 생성하고 안에 conf 폴더를 생성 후 nginx.conf 파일을 생성한다.
upstream server1 {
server 172.17.0.2:80;
}
upstream server2 {
server 172.17.0.3:80;
}
server {
listen 80;
server_name localhost;
location /server1 {
proxy_pass http://server1/;
}
location /server2 {
proxy_pass http://server2/;
}
}
upstream server1, upstream server2 : upstream 블록을 작성해서 2개의 서버의 IP 주소와 포트를 설정한다. 각각의 IP 주소는 docker inspect {컨테이너 아이디} 명령어를 실행하고 IPAddress 부분을 확인해보면 알아낼 수 있다.location /server1, location /server2 : ‘/server1’로 들어오는 요청은 ‘http://server1/’로, ‘/server2’로 들어오는 요청은 ‘http://server2’로 프록시되게끔 설정한다. 각 url에서 server1, server2는 각각 upstream 블록에서 명시한 IP 주소와 포트로 치환된다.FROM nginx
COPY conf/nginx.conf /etc/nginx/conf.d/default.conf
ENTRYPOINT ["nginx", "-g", "daemon off;"]
lb 폴더의 Dockerfile에는 작성한 nginx.conf 파일이 /etc/nginx/conf.d/default.conf 파일로 덮어씌워지게끔 COPY 명령어를 사용한다.
$ docker build -t lb ./lb
$ docker run -d -p 8080:80 lb
이미지를 빌드하고 8080포트로 포트 포워딩해 실행시킨다. 이제 http://localhost:8080/server1 로 요청할 경우 server1의 index.html 파일의 내용이, http://localhost:8080/server2 로 요청할경우 server2의 index.html 파일의 내용이 화면에 나타난다.

최종 폴더 구조는 위와 같다.
upstream server1 {
server 172.17.0.1:8001; # 게이트웨이 주소로 변경
}
upstream server2 {
server 172.17.0.1:8002; # 게이트웨이 주소로 변경
}
server {
listen 80;
server_name localhost;
location /server1 {
proxy_pass http://server1/;
}
location /server2 {
proxy_pass http://server2/;
}
}
위에서 작성한 lb/nginx.conf 파일의 내용이다.
upstream 블록의 server1, server2의 IP:포트번호를 Nginx의 게이트웨이 주소(172.17.0.1)를 사용하여 변경하였다.
도커를 사용하여 MySql 컨테이너를 생성하고 MySql의 환경변수를 설정해보자.
MySql 환경변수를 통해 사용자, 사용자 비밀번호, root 비밀번호, 시작할 때 생성할 데이터베이스의 이름 등을 설정할 수 있다.
$ docker run -d -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=firstdb mysql
Dockerfile을 사용하지 않는다면 위 명령어와 같이 -e 옵션을 통해서도 환경변수를 설정할 수 있다.
하지만 Dockerfile로 만들어 놓는다면 긴 명령어를 작성할 필요 없이 하나의 파일을 통해 컨테이너를 생성하고 환경변수를 설정할 수 있다.
FROM mysql
ENV MYSQL_USER=user
ENV MYSQL_PASSWORD=user1234
ENV MYSQL_ROOT_PASSWORD=root1234
ENV MYSQL_DATABASE=firstdb
CMD ["--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci"]
ENV 명령어를 통해 MySql의 환경변수를 설정하고 CMD 명령어를 통해 MySql의 캐릭터셋을 설정했다.
docker exec -it {컨테이너 아이디} 명령어를 통해 mysql 컨테이너의 터미널로 접속한다.
$ echo $MYSQL_USER
$ echo $MYSQL_PASSWORD
$ echo $MYSQL_ROOT_PASSWORD
$ echo $MYSQL_DATABASE
echo 명령어를 통해 설정되어 있는 환경변수를 확인한다.
Dockerfile에서 설정한 환경변수들이 잘 출력된다.
도커는 데이터베이스 컨테이너를 생성할 때 일반적으로 데이터베이스 컨테이너가 사용하는 데이터를 영속적으로 사용하기 위해 볼륨을 생성한다.
데이터베이스 컨테이너를 생성하거나 다시 실행시킬 때 도커 드라이버의 볼륨 혹은 호스트 머신의 볼륨 파일을 연결할 수도 있다.
$ docker volume ls
mysql 컨테이너를 생성한 후에 docker volume ls 명령어를 입력하면 볼륨 리스트를 확인할 수 있다.
$ docker run -d -v {volume이름}:/var/lib/mysql mysql
-v 옵션을 통해 기존의 volume 이름을 지정하고 mysql 컨테이너의 /var/lib/mysql 경로와 연결해준다. 기존에 존재하던 볼륨을 mysql과 연결해줄 수 있다.
만약 지정한 이름의 volume이 존재하지 않는다면 해당 이름으로 새로운 볼륨을 생성해 연결시켜준다.
$ docker run -d -v {호스트머신의 볼륨경로}:/var/lib/mysql mysql
호스터머신의 볼륨으로 사용할 경로/파일을 지정하면 해당 경로/파일을 볼륨으로 mysql 컨테이너에 연결할 수 있다.
(MySql 컨테이너의 볼륨경로는 /var/libs/mysql로 정해져있다.)
메타코딩 유튜브의 Docker 강의를 듣고 요약한 내용입니다. (강의 적극 추천)