다음의 조건을 활용하여 배포된 컨테이너는 접속 즉시 설치 페이지에서 설치 후 게시판을 사용할 수 있어야 한다.
이미지 컨테이너
--------------------------------------------------------------------
centos:7을 base로 하여 xe:1.0 이미지를 만들어야 함 xe 컨테이너(xe1)
mysql 5.7 db 컨테이너(db1)
xe1 --(link)-- db1
(80) (3306)
|
8888
rapa@rapa:~$ docker run -d \
> --name db1 \
> -e MYSQL_ROOT_PASSWORD=test123 \
> -e MYSQL_DATABASE=xe \
> mysql:5.7
7fdae8c3a8279cb3872da7fdb523f96997917794dcf9a107450df8b5ac38134c
rapa@rapa:~$ vi Dockerfile
FROM centos:7
RUN yum clean all
RUN yum update -y
RUN yum -y install wget git httpd
RUN wget http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
RUN yum -y localinstall remi-release-7.rpm
RUN yum -y install epel-release yum-utils
RUN yum-config-manager --enable remi-php74
RUN yum -y install php php-fpm php-gd php-mysql php-xml
RUN git clone https://github.com/xpressengine/xe-core.git /var/www/html/xe
WORKDIR /var/www/html/xe
WORKDIR /var/www/html
RUN chmod -R 707 xe
RUN chown -R apache:apache xe # xe 디렉토리의 권한이 apache 소유로 됨
EXPOSE 80
CMD httpd -D FOREGROUND
rapa@rapa:~$ docker build -t xe:1.0 .
rapa@rapa:~$ docker run -it \
> --name xe1 \
> --link db1:mysql \
> -p 8888:80 \
> xe:1.0
[가상머신의 ip주소]:8888/xe 또는, 가상 머신에서 localhost:8888/xe 접속
DB 호스트 네임은 db 컨테이너의 이름(db1)으로 입력
설정을 완료하면 메인 페이지가 뜬다.
이미지 저장소
사설 저장소:
version 1: python
version 2: go (일반적으로 version2를 사용한다)
참고: https://docs.docker.com/registry/deploying/
rapa@rapa:~/0819/board$ docker pull registry
rapa@rapa:~/0819/board$ docker pull hyper/docker-registry-web
rapa@rapa:~$ docker container run -d \
> -p 5000:5000 \
> --restart=always \
> --name registry \
> -v /home/rapa/registry:/var/lib/registry \
> registry
17ec4290f1d22ee8b30553f74a84c27602202e8c7e26f361464302e849d9cf0a
rapa@rapa:~$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
17ec4290f1d2 registry "/entrypoint.sh /etc…" 30 seconds ago Up 28 seconds 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp registry
일반적으로 이미지의 이름은 아래와 같은 형식을 취해야 한다.
goyangyee/myweb:1.0
reg.test.com:5000/myweb:1.0
또는
192.168.101:5000/myweb:1.0
myweb:1.0
rapa@rapa:~$ docker tag centos:7 \
> localhost:5000/mycentos:1.0
rapa@rapa:~$ docker push localhost:5000/mycentos:1.0
The push refers to repository [localhost:5000/mycentos]
174f56854903: Pushed
1.0: digest: sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f size: 529
rapa@rapa:~$ ls /home/rapa/registry/docker/registry/v2/repositories/mycentos/
_layers _manifests _uploads
rapa@rapa:~$ curl -XGET localhost:5000/v2/_catalog
{"repositories":["mycentos"]}
-> curl을 통해 확인하기는 불편하니 GUI를 지원하는 hyper/docker-registry-web를 구성해보자.
rapa@rapa:~$ docker run -d \
> -p 8080:8080 \
> --name registry-web \
> --link registry:private \
> -e REGISTRY_URL=http://211.183.3.116:5000/v2 \
> -e REGISTRY_NAME=211.183.3.116:5000 \
> --restart=always \
> hyper/docker-registry-web
7aa7f49a8154260e4c25d1559b8f1800e4013018efea5ef6e15888d33432ae25
[가상머신의 ip주소]:8080 또는, 가상 머신에서 localhost:8080 접속
이미지가 push 된 모습을 확인할 수 있다.
rapa@rapa:~$ docker image rm -f localhost:5000/mycentos:1.0
Untagged: localhost:5000/mycentos:1.0
Untagged: localhost:5000/mycentos@sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f
rapa@rapa:~$ docker pull localhost:5000/mycentos:1.0
1.0: Pulling from mycentos
Digest: sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f
Status: Downloaded newer image for localhost:5000/mycentos:1.0
localhost:5000/mycentos:1.0
rapa@rapa:~$ docker image ls | grep mycentos
localhost:5000/mycentos 1.0 eeb6ee3f44bd 11 months ago 204MB
-> 사설 저장소에서 pull이 잘 된다.
--insecure-registry는 보안 상 좋지 않음! 편의를 위해서는 좋다.
로컬에서 원격지에 있는 사설 저장소로 접속하기 위해서는 사설 저장소에 인증정보를 전달해야 한다. 인증 정보는 config.json 파일에서 확인한다. 인증 정보가 없다면 해당 접근을 차단시킨다. --insecure-registry는 인증 정보가 없어도 접속하도록 허용하겠다.
192.168.1.116:5000/myweb:gunwoo
rapa@rapa:~$ docker container run -d \
> -p 5000:5000 \
> --restart=always \
> --name registry \
> -v /home/rapa/registry:/var/lib/registry \
> registry
4b5f9237fd4b47c10bc1ff293448fdbd5d074e2339f9b3c5232da99b20ca3bbf
rapa@rapa:~$ docker run -d \
> -p 8080:8080 \
> --name registry-web \
> --link registry:private \
> -e REGISTRY_URL=http://192.168.1.116:5000/v2 \
> -e REGISTRY_NAME=192.168.1.116:5000 \
> --restart=always \
> hyper/docker-registry-web
52d3411d2809132b1425e5a545b77e4af15118687b5605df6ee207e5c21a91d8
rapa@rapa:~$ docker tag centos:7 \
> 192.168.1.117:5000/myweb:gunwoo
.117 (JH님) 레지스트리에 등록할 이미지
myweb에 gunwoo라는 태그로 push할 것임
rapa@rapa:~$ sudo vi /etc/init.d/docker
DOCKER_OPTS=--insercure-registry 192.168.1.117:5000
rapa@rapa:~$ sudo vi /etc/docker/daemon.json
{ "insecure-registries": ["192.168.1.117:5000"] }
rapa@rapa:~$ sudo service docker restart
rapa@rapa:~$ docker push 192.168.1.117:5000/myweb:gunwoo
The push refers to repository [192.168.1.117:5000/myweb]
174f56854903: Pushed
gunwoo: digest: sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f size: 529
JH님 레지스트리에 내 이미지가 push 되었음
참고: --insecure-registry 등록을 안 한다면 아래와 같은 오류가 발생한다.
rapa@rapa:~$ docker push 192.168.1.117:5000/myweb:gunwoo
The push refers to repository [192.168.1.117:5000/myweb]
Get "https://192.168.1.117:5000/v2/": http: server gave HTTP response to HTTPS client
별도의 인증 서버(LDAP)를 사용함
일반적으로 웹서비스는 3tier 구조를 갖는다.
-> WEB -> WAS -> DB
위와 같은 구조를 docker container run을 이용하여 구성하게 되면
1) 복잡하다
2) 동일 구조를 다시 만드는데 오랜 시간이 걸린다.
3) 변경이 용이하지 않다.
위와 같은 구조를 하나의 명세서에 작성하는 방법을 도커에서 제공하는데 이를 docker-compose라 부른다. docker-compose는 docker에서 제공하는 기본 서비스가 아니므로 별도로 추가 설치가 필요하다.
단, docker-compose는 클러스터 환경에서의 사용이 아니라 1대의 도커 서버에서 동작한다.
실제 클러스터 환경에서는 docker-compose + 클러스터 환경(docker swarm) = "docker stack"
명세 파일에 아래의 오브젝트를 구성하게 된다.
service -> 컨테이너
volume
network
rapa@rapa:~$ docker network ls
NETWORK ID NAME DRIVER SCOPE
217d4994d23b bridge bridge local
3ead376f089f host host local
39430d1f4412 none null local
rapa@rapa:~$ docker network create private1
a1e4edb3fffb2cb1a51aa5198709261bc6a60af12d9b87f76f5c4cb1421fb7f2
rapa@rapa:~$ docker network ls
NETWORK ID NAME DRIVER SCOPE
217d4994d23b bridge bridge local
3ead376f089f host host local
39430d1f4412 none null local
a1e4edb3fffb private1 bridge local
rapa@rapa:~$ docker network create \
> --driver bridge \
> --subnet 10.10.0.0/16 \
> --ip-range 10.10.10.0/24 \
> --gateway 10.10.10.1 \
> private2
3db02bb3bc0641040071ffb11c3184d1cd8d69ec66f646ea7ed9d90d9bbc12d0
-> 서브넷, ip 범위, gateway를 지정함
rapa@rapa:~$ docker container run -it \
> --name centos11 \
> --net=private2 \
> --ip=10.10.10.10 \
> centos:7 /bin/bash
[root@e0d0d5e38844 /]#
-> private2 네트워크의 서브넷을 지정했기 때문에 ip를 직접 할당할 수 있음
[root@e0d0d5e38844 /]# ping www.google.com -c 3
PING www.google.com (172.217.175.228) 56(84) bytes of data.
64 bytes from nrt12s29-in-f4.1e100.net (172.217.175.228): icmp_seq=1 ttl=110 time=34.9 ms
64 bytes from nrt12s29-in-f4.1e100.net (172.217.175.228): icmp_seq=2 ttl=110 time=32.1 ms
64 bytes from nrt12s29-in-f4.1e100.net (172.217.175.228): icmp_seq=3 ttl=110 time=33.0 ms
--- www.google.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 32.123/33.377/34.946/1.192 ms
[root@e0d0d5e38844 /]#
rapa@rapa:~$ docker container inspect centos11 | grep 10.10.10.10
"IPv4Address": "10.10.10.10"
"IPAddress": "10.10.10.10",
rapa@rapa:~$
rapa@rapa:~$ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 12.1M 100 12.1M 0 0 4943k 0 0:00:02 0:00:02 --:--:-- 5429k
rapa@rapa:~$ sudo chmod +x /usr/local/bin/docker-compose
rapa@rapa:~$ docker-compose --version
docker-compose version 1.29.2, build 5becea4c
rapa@rapa:~$ vi .bashrc
alias dc='docker-compose'
-> 위 코드 추가하기
rapa@rapa:~$ source .bashrc
rapa@rapa:~$ dc -v
docker-compose version 1.29.2, build 5becea4c
도커 컴포즈
docker container run 명령들을 YAML 파일에 작성하는 것
다음의 사항을 정의한다.
version: 버전별로 지원되는 옵션이 달라진다. 지원이 되지 않는 등의 문제가 있다면 해당 버전을 홈페이지에서 반드시 확인해야 한다.
service: 실제로 서비스를 제공하는 컨테이너에 대한 정의
volume: 컨테이너에 연결할 볼륨을 정의한다. (필수 아님)
network: 컨테이너들을 연결할 네트워크를 정의한다. (필수 아님. 작성하지 않으면 모든 컨테이너는 docker0에 연결된다)
각 항목의 하위 항목을 정의하려면 들여쓰기 매우매우 중요함
일반적으로 yaml 파일은 tab을 인식하지 못한다. 반드시 space bar를 이용해야 한다.
하나의 컴포즈 파일에 작성된 서비스들은 자동으로 link가 된다.
버전 정의:
version: '3.9'
서비스 정의:
services:
myctn1:
image: centos:7
environment:
MYSQL_ROOT_PASSWORD: test123
MYSQL_DATABASE: wordpress
networks:
- private1
- pirvate2
myctn2:
build: .
environment:
- WORDPRESS_DB_USER=root
- WORDPRESS_DB_NAME=wordpress
depends_on: # 실행 순서 결정. myctn2가 실행되기 전에 myctn1이 먼저 실행됨. 하지만 myctn1의 동작 완료를 확인하지는 않음.
- myctn1
ports:
- "8080:80" # 시간을 의미하는 12시 30분과 구분하기 위해 일반적으로 " "을 붙인다.
- "33061:3306" # -p 33061:3306
- "8080" # -P 8080 -> 호스트의 랜덤 포트와 컨테이너의 8080을 연결
- "8081-8085" # 호스트의 랜덤 포트와 컨테이너의 8081-8085를 연결
networks:
- private2
image 옆에는 실제 이미지의 이름을 쓴다.
build 옆에는 도커파일의 경로를 쓴다.
ex) ctn2 -> ctn3 -> ctn1 순서로 실행을 하고 싶을 떄 depends_on 설정?
ctn1 3rd -> depends_on: ctn2, ctn3
ctn2 1st
ctn3 2nd -> depends_on: ctn2
네트워크 정의:
networks:
private1:
driver: bridge # private1은 브릿지 타입으로 생성된다.
external: true # 기존에 만들어두었던 private1을 활용한다.
rapa@rapa:~/0819$ vi docker-compose.yml
version: "3.0"
services:
wordpress:
image: wordpress
ports:
- "8888:80"
environment:
- WORDPRESS_DB_PASSWORD=test123
- WORDPRESS_DB_NAME=wpdb
- WORDPRESS_DB_USER=root
depends_on:
- db
links:
- db:mysql
db:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=test123
- MYSQL_DATABASE=wpdb
-> wordpress 컨테이너와 mysql 컨테이너(db) 배포
-> wordpress는 8888 포트로 외부 접속 허용
rapa@rapa:~/0819$ dc up -d
Creating network "0819_default" with the default driver
Creating 0819_db_1 ... done
Creating 0819_wordpress_1 ... done
rapa@rapa:~/0819$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
50d1cef7555f wordpress "docker-entrypoint.s…" 3 minutes ago Up 3 minutes 0.0.0.0:8888->80/tcp, :::8888->80/tcp 0819_wordpress_1
6f40391539bd mysql:5.7 "docker-entrypoint.s…" 3 minutes ago Up 3 minutes 3306/tcp, 33060/tcp 0819_db_1
[가상머신의 ip 주소]:8888 접속, 또는 가상 머신에서 localhost:8888 접속
컨테이너의 이름에는 docker-composer에서 배포했던 경로가 앞에 붙는다.
컨테이너의 이름 뒤에는 숫자가 붙는다. scale을 통해 여러 개의 컨테이너를 배포하면 순서대로 숫자가 부여된다.
docker compose + docker swarm(cluster) = swarm mode(docker stack)
이미지 만들기(자체는 할 수 있는게 없음)
Dockerfile 명령어
RUN apt-get install -y apache
CMD apache2tcl -D FOREGROUND
ADD http://www.test.com/index.php /var/www/html
ADD test.tar /var/www/html
ONBUILD ADD blog.tar /var/www/html/
ENV A="Hello"
컨테이너에서 "env" 명령을 실행하면 A="Hello"가 보인다.
EXPOSE 3331
docker run -p를 이용하여 호스트의 포트와 매핑해주면 외부에서 해당 포트로 접근이 가능해진다.
docker run \
-p 3331:3333
VOLUME /var/log
-> 컨테이너의 /var/log를 호스트의 임의의 볼륨(ID)과 연결한다.
VOLUME /var/www/html /root
-> 컨테이너의 /var/www/html, /root 디렉토리를 호스트의 임의의 두 볼륨과 각각 연결한다.
VOLUME testvolume:/var/log
-> 여러 컨테이너들이 생성 될 때마다 호스트의 testvolum과 연결됨. 좋은 방법이 아니기 때문에 쓰지 말자!
ONBUILD ADD test.tar /usr/share/nginx/html/
docker 명령어
docker build -t myweb:1.0 .
docker tag myweb:1.0 \
goyangyww/myweb:1.0
docker push goyangyww/myweb:1.0
-> 사전에 정상 로그인되면 로그인 정보(api주소 + auth 정보)가 홈 디렉토릐 > .docker > config.json 파일에 작성된다.
docker login http://211.183.3.111
docker tag myweb:1.0 \
211.183.3.111:5000/myweb:1.0
docker push 211.183.3.111:5000/myweb:1.0
compose: 1대의 노드에서 동일한 컨테이너를 여러 개 만들 수 있다.
httpd1 -> httpd2
| |
db1 -> db2
version: "3.5"
services:
web: a_web_1 -> web2 -> web3
db:
networks:
volumes: