在要離開 docker container 的 terminal 時有一個坑。就是如果輸入 exit 指令時,container 會被關閉,如下圖:
如果不要停止 container 而要退出 docker container 的terminal 需要輸入 ctrl + p之後再輸入 ctrl + q 的按鍵 ,就不會把 container 關閉。
FROM centos:7
MAINTAINER Neil
RUN yum install -y wget
RUN cd /
ADD jdk-12.0.2_linux-x64_bin.tar.gz /
RUN wget http://apache.stu.edu.tw/tomcat/tomcat-7/v7.0.94/bin/apache-tomcat-7.0.94.tar.gz
RUN tar zxvf apache-tomcat-7.0.94.tar.gz
ENV JAVA_HOME=/jdk-12.0.2
ENV PATH=$PATH:/jdk-12.0.2/bin
CMD ["/apache-tomcat-7.0.94/bin/catalina.sh", "run"]
FROM: 使用到的 Docker Image 名稱,今天使用 CentOS
MAINTAINER: 用來說明,撰寫和維護這個 Dockerfile 的人是誰,也可以給 E-mail的資訊
RUN: RUN 指令後面放 Linux 指令,用來執行安裝和設定這個 Image 需要的東西
ADD: 把 Local 的檔案(要與Dockerfile同目錄) 複製到 Image 裡,如果是 tar.gz 檔複製進去 Image 時會順便自動解壓縮。Dockerfile 另外還有一個複製檔案的指令 COPY 未來還會再介紹
ENV: 用來設定環境變數
CMD: 在指行 docker run 的指令時會直接呼叫開啟 Tomcat Service
複製本地端的檔案/目錄到映像檔的指定位置中
使用COPY的注意事項:
指令的來源位置可以多個
如果目的位置是目錄的話,記得最後要以/結尾,例如:/mypath/
目的位置可以是絕對路徑或者相對於WORKDIR定義值的相對路徑
若目的位置不存在,會自動建立
COPY的範例如下:
COPY file1.txt file2.js file3.json ./
COPY ["file1.txt", "file2.js", "file3.json" "./"]
和COPY一樣,可將本地端的檔案/目錄加到映像檔的指定位置內
雖然ADD和CMD功能類似,但有二點最大的不同:
ADD的來源路徑支援URL,也就是說可以加入遠端的檔案,COPY則不支援URL
若來源檔案是壓縮檔(副檔名為gzip、bzip2、xz),則使用ADD加入檔案時會自動解壓縮,而COPY不會
ADD的範例如下:
ADD file1.txt file2.js file3.json ./
ADD https://www.google.com/demo.gzip $ENV_DEMO_VALUE
ENV_DEMO_VALUE 是用ENV指令所設定的環境變數
預設在和 Dockerfile 檔案同層的資料夾底下輸入, docker build 指令,如下
$ docker build -t mytomcat . --no-cache
使用 –no-cache 的主要原因,是避免在 Build Docker image 時被 cache 住,而造成沒有 build 到修改過的 Dockerfile。
Build 完 Docker Image 之後,使用 docker images 指令查看是否有 build 成功如下圖
之後就可以執行 Docker Container,這時Tomcat 的 Service 也會跟者被執行起來,指令如下
$ docker run mytomcat
要打開 Browser 確認 Tomcat Service 有沒有被執行起來時,發現我們不知道 Docker Container 的 IP,這時侯只能使用 docker exec 進入 docker container查詢 IP 。
要使用 docker exec 指令之前需要先知道 Container 的 ID 所以需要先使用 docker ps 指令查詢 Container ID,如下圖:
有了 IP 之後就可以打開 Browser 輸入 http://172.17.0.2:8080 URL的位置,確認 Tomcat Service 是否有啟動,如下圖:
$ docker run -p 8080:8080 mytomcat
Container 的 8080 port mapping到 localhost 的 8080 port ,這樣只要輸入
http://localhost:8080 就可以看到 tomcat service 的 WebUI 畫面了。
$ docker tag mytomcat jackyohhub/mytomcat
使用的Docker tag格式如下:
docker tag ${Image Name} DockerHub帳號/Image Name
執行結果的畫面如下:
$ docker push jackyohhub/mytomcat
成功之後的畫面如下
$ docker rmi -f jackyohhub/mytomcat
$ docker rmi -f mytomcat
$ docker pull jackyohhub/mytomcat
docker run -p 8080:8080 jackyohhub/mytomcat
直接透過啟動 Docker container 的方式,就可以把 Docker Registry Server 建立起來,指令如下:
$ docker run -d -p 5000:5000 -v /home/user1/storage:/var/lib/registry --name registry registry:2
參數說明如下:
-d:執行的 docker container 是 run 在背景的狀態,所以需要使用 docker logs 的指令才可以看到 log 狀態
-p:主機的 5000 port mapping 到 container 的 5000 port
-v:因為 push 到 docker registry 的資料是放在 container 裡面的,如果把 docker container 刪除掉 docker registry 的 Image 資料就會不見,因此需要使用 –v 參數將主機的檔案路徑 mapping 到 container 裡面的檔案路徑,這樣 docker container 被刪除 docker registry 的 Image 資料還會存在
–name:設定 docker container 的名稱
執行成功之後畫面如下:
跟使用 docker hub 一樣要把 Docker Image Push 到 Docker需要先使用 docker tag 的指令如下:
$ docker tag mytomcat 192.168.182.134:5000/mytomcat
因為這裡是 Demo 所以直接使用 IP 位址指定 Docker Reigstry 的位址,在實務上這是 Hard Code的做法,所以較好做法應該是使用指定 Host Name的方式。
把 Docker Image Push 到 Docker Registry Server 上,指令如下:
$ docker push 192.168.182.134:5000/mytomcat
畫面如下:
在上個步驟把 Docker Image Push 到 Docker Registry 收到錯誤訊息主要是因為安全性上的問題,需要修改 client 的 Docker 設定,如下
(1) vi /etc/docker/daemon.json
daemon.json 的檔案內容如下
{
"live-restore": true,
"group": "dockerroot",
"insecure-registries": ["192.168.182.134:5000"]
}
(2) 重新啟動 Docker 的 service 指令如下
$ systemctl restart docker
重新 push docker image,指令如下
$ docker push 192.168.182.134:5000/mytomcat
可以看到畫面如下
以上就成功的把 Docker Image Push 到了 Docker Hub 上了
需要修改 docker 的設定,如下
$ vi /etc/docker/daemon.json
daemon.json 的檔案內容如下
{
"live-restore": true,
"group": "dockerroot",
"insecure-registries": ["192.168.182.134:5000"]
}
重新啟動 Docker 的 service 指令如下
$ systemctl restart docker
Pull docker image 指令如下
$ docker pull 192.168.182.134:5000/mytomcat
執行成功之後畫面如下
使用以下的指令將 Docker Image 存檔出一個檔案如下
$ docker save -o mytomcat.tar mytomcat
參數說明如下:
-o: 輸出檔案
mytomcat 是 Docker Image 的名稱
畫面如下:
在這過程可能會需要花費一些時間,執行完成之後就可以看到產生出 mytomcat.tar的檔案
(儲存所有images
$ docker save $(docker images -q) -o myimages.tar )
把檔案 Load 到 Docker 的指令如下
$ docker load -i mytomcat.tar
參數說明如下:
-i: 放要 import 的檔案名稱
畫面如下:
*使用以下指令啟動 Docker container
$ docker run -d -p 8080:8080 mytomcat
畫面如下
在 Browser 上輸入 http://192.168.182.130:8080 看到 tomcat 畫面,就可以確認 Docker container 有啟動起來,畫面如下
今天已經介紹了如何備份 Docker Image 的部份了,適合在沒有網路而且只需要個人使用的情況下使用。
Host1 的實體主機需要連線到 Host2 的實體主機裡面的 Container1,如果在沒有設定網路情況下 Host1 連不到 Host2,因為 Container1 是被保護在 Host2 實體機器裡,如果要讓 Host1 連到 Host2 上,最簡單的方法是先讓 Host2 的 Port 對應到 Container1 的 Port,然後 Host1 會先連到 Host2 實體主機的 Port,然後就會對應到 Container1 的 Port,這樣 Host1 就可以連到 Host2 上的 Container1,這是最常使用的方法。
測試在使用 docker run 指令時參數指定為大寫的 -P,這樣實體主機會隨機的產生一個 Port 對應到 Container 裡面的 Port,但在這之前需要修改一下 Dockerfile,實作的步驟如下:
FROM centos:7
MAINTAINER Neil
RUN yum install -y wget
RUN cd /
RUN wget http://apache.stu.edu.tw/tomcat/tomcat-7/v7.0.94/bin/apache-tomcat-7.0.94.tar.gz
RUN tar zxvf apache-tomcat-7.0.94.tar.gz
CMD ["/apache-tomcat-7.0.94/bin/catalina.sh", "run"]
EXPOSE 8080
EXPOSE 就是宣告有 8080 Port,在執行 Docker Container時需要把它開放出去
$ docker build -t tomcatporttest .
$ docker run -d -P tomcatporttest
$ docker ps -a
$ docker port [CONTAINER ID]
2fec91391edb 為 ContainerID
使用 Example1 的 Docker Image,在執行 docker run 時,指定小寫的-p參數,指令如下:
$ docker run -d -p 8080:8080 tomcatporttest
左邊的 8080 Port 代表指定實體主機的 Port,對應到右邊 Container 裡面的 8080 Port,畫面如下:
啟動 container1 的 Docker Container,然後再啟動 container2 並且 link 到 container1,最後測試看看直接在 container2 上是否 ping 得到 container1,步驟如下:
$ docker run -it --name container1 centos /bin/bash
$ docker run -it --name container2 --link container1 centos /bin/bash
上圖主要是說明 Host1 實體主機裡面有 Container1,然後 Host2 實體主機裡面有 Container2,可以透過 Docker Overlay 的 Network 的模式將 Container1 和 Container2 連接起來做溝通。另外 Consol 是一個存放連線資訊的資料庫,在使用 overlay 時必需要在 Docker 設定,這樣才能存放 overlay 網路模式的連線資訊。
另外在使用 overlay 網路模式時,要先確認 Linux Kernel 的版本。目前我使用的版本是 3.19.8 是可以正常執行的。
Example:
使用 Docker Overlay的網路模式,實作不同的實體主機之間的 container 可以互相的連接,步驟如下:
切換到 root 使用者,修改 Host1 的 Docker 設定,指令如下:
$ vi /etc/docker/daemon.json
設定檔如下
{
"live-restore": true,
"group": "dockerroot",
"hosts": [
"unix:///var/run/docker.sock",
"tcp://10.1.0.221:2375"
],
"cluster-store": "consul://10.1.0.221:8500",
"cluster-advertise": "enp8s0:2375"
}
主要的設定就是 cluster-store 和 cluster-advertise,分別是要連接到 consul 的 service,取得 overlay 網路模式的連線資訊,以及設定可以讓不同實體主機連線的網路卡。
重新啟動 Host1 的 Docker Service 指令如下:
systemctl restart docker
docker run -d -p 8500:8500 progrium/consul -server -bootstrap
docker network create -d overlay overlay1
使用 docker network ls,查看建立之後的結果,畫面如下
docker run -it --name=container1 --net=overlay1 busybox
開一個新視窗,到 Host2 修改 Docker 的設定如下
$ vi /etc/docker/daemon.json
設定如下:
{
"live-restore": true,
"group": "dockerroot",
"hosts": [
"unix:///var/run/docker.sock",
"tcp://10.1.0.223:2375"
],
"cluster-store": "consul://10.1.0.221:8500",
"cluster-advertise": "enp8s0:2375"
}
以上的設定和 Host1 是很像的
在 Host2 上重新啟動 Docker service 指令如下
$ systemctl restart docker
在 Host2 上,使用 docker network ls 指令確認是否有連到 consol service,畫面如下
在 Host2 上啟動一個 container,並且連到 overlay1 的網路,指令如下
$ docker run -it --name=container2 --net=overlay1 busybox
利用docker-compose啟動開發環境需要的服務
來看下面我用來啟動eureka, hystrix, rabbitmq的例子
version: '3'
services:
eureka:
image: springcloud/eureka:latest
container_name: eureka-server
depends_on:
- "rabbitmq"
ports:
- "8761:8761"
hystrix:
image: kennedyoliveira/hystrix-dashboard:latest
container_name: hystrix-dashboard
depends_on:
- "rabbitmq"
ports:
- "7979:7979"
rabbitmq:
image: rabbitmq:3-management
container_name: rabbitmq
ports:
- "5672:5672"
- "15672:15672"
volumes:
networks:
先從大分區來看
version, services, volumes, networks
version: 這個docker-compose對應到的docker版本,不同版本指令略有區別
services: 就是容器的各項設定
image: 指定用來啟動的image
container_name: 啟動後的容器名稱
depend_on: 等待特定容器先啟動完成(啟動順序的安排),在這個例子中我先啟動RabbitMQ才啟動其他兩個
ports: locallost跟containers的port映射
volumes: 共用儲存空間的設定, 就是data volume
networks: 容器間內部網路的設定
由於沒有database又是透過主機的port連線,所以沒有內容
一行docker-compose up就讓我在利用steeltoeoss開發中需要的環境啟動完成
利用docker-compose啟動的過程中,產生新的image再啟動container
注意最下面的productservice,apigateway
version: '3'
services:
eureka:
image: springcloud/eureka:latest
container_name: eureka-server
depends_on:
- "rabbitmq"
ports:
- "8761:8761"
hystrix:
image: kennedyoliveira/hystrix-dashboard:latest
container_name: hystrix-dashboard
depends_on:
- "rabbitmq"
ports:
- "7979:7979"
rabbitmq:
image: rabbitmq:3-management
container_name: rabbitmq
ports:
- "5672:5672"
- "15672:15672"
productservice:
image: productservice:latest
container_name: productservice
build:
context: ./productservice
depends_on:
- "eureka"
apigateway:
image: apigateway:latest
container_name: apigateway
environment:
- BUILD=LOCAL
build:
context: ./apigateway
depends_on:
- "rabbitmq"
- "hystrix"
利用build指令,可以切換到不同目錄下然後以該目錄底下的dockerfile進行編譯後發行image, 再依據最新的image啟動容器。當然docker-compose的步驟可以靠寫批次檔完成,但不會像使用docker-compose搭配yml這麼方便管理,利用docker-compose在localhost一次啟動所有開發所需的服務,這個還蠻實用的,當你的服務越來越多,可以幫你省下不少手動啟動跟環境設置的時間。
再一個空目錄下建立nginx 和php兩個目錄,首先進入nginx目錄並建立一個Dockerfile檔案
cd nginx
vi Dockerfile
在Dockerfile檔案中寫入如下指令
FROM nginx:latest
COPY default.conf /etc/nginx/conf.d/default.conf
儲存Dockerfile檔案後再建立一個default.conf內容為
#以下內容僅供參考,請按實際環境定製
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm index.php;
location ~ \.php$ {
fastcgi_pass php-fpm:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html/$fastcgi_script_name;
include fastcgi_params;
}
}
儲存檔案後再執行 cd ../php 進入php目錄 編輯Dockerfile檔案(主要增加了一些常用擴充套件,請按實際情況定製) 內容如下
FROM php:7.3-fpm
RUN docker-php-ext-install pdo pdo_mysql mysqli \
&& pecl install redis-4.2.0 && docker-php-ext-enable redis
然後儲存,cd .. 回到外層目錄建立docker-compose.yml檔案
vi docker-compose.yml 並鍵入如下內容
version: '3'
networks:
dev-net:
driver: bridge
services:
mysql:
image: mysql:latest
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
networks:
- dev-net
nginx:
build: nginx
restart: always
ports:
- 80:80
volumes:
- /home/wwwroot/default/:/usr/share/nginx/html
depends_on:
- mysql
- redis
- php-fpm
networks:
- dev-net
php-fpm:
build: php
volumes:
- /home/wwwroot/default/:/usr/share/nginx/html
networks:
- dev-net
redis:
image: redis:latest
networks:
- dev-net
儲存後執行
docker-compose up -d
等待完成自動構建即可
docker pull mysql:5.7 (最新版的會有加密登入問題)
有時候需要先刪除一些port
sudo pkill mysql
sudo pkill mysqld
以下為進入local端
docker stop my-mysql
docker start my-mysql
以下為進入容器
docker inspect log_db 檢查對外連線ip
FROM ubuntu:18.04
RUN apt-get update -y && apt install nodejs -y && apt install npm -y
WORKDIR /app
COPY . .
CMD ["npm", "run", "serve"]
EXPOSE 8080
Name, | shorthand | Default Description |
---|---|---|
–all , | -a | Show all containers (default shows just running) |
–filter , | -f | Filter output based on conditions provided |
–format | Pretty-print containers using a Go template | |
–last , | -n -1 | Show n last created containers (includes all states) |
–latest , | -l | Show the latest created container (includes all states) |
–no-trunc | Don’t truncate output | |
–quiet , | -q | Only display numeric IDs |
–size , | -s | Display total file sizes |
-d | Daemonized 背景執行container | |
-P | 隨機port映射,容器內部port隨機映射到主機的port | |
-p | 指定port映射,格式為:主機(外網):容器(內網) | |
-volume , | -v | 將主機的檔案路徑 mapping 到 container 裡面的檔案路徑,這樣 docker container 被刪除 docker registry 的 Image 資料還會存在 ex: docker run -v /主機/的路徑:/image/的路徑 image |
-i | –interactive (互動模式) 當跑的程序需要監聽輸入的時候可加入 ex: docker run -i image | |
-t, –tty | 配置一個終端機 | |
-it | 互動模式通常會搭配終端機,ex: docker run -it image | |
–restart=always: | 如果 container 遇到例外的情況被 stop 掉,例如是重新開機,docker 會試著重新啟動此 container | |
-e | 設定docker image的環境變數 ex: docker run -e APP_COLOR=red image |
docker start [OPTIONS] CONTAINER [CONTAINER…]
docker stop [OPTIONS] CONTAINER [CONTAINER…]
docker restart [OPTIONS] CONTAINER [CONTAINER…]
等同強制停止container
(1)會試著在 local 裡找有沒有 nginx Docker Image,如果沒有會自動的從 Docker Hub 上 pull 下來
(2)有了 Docker Image 之後從會mount Init設定 Container 系統和 mount 可讀可寫層
(3)Container 啟動完成
docker run 指令時,指定 -v 參數,使得實體主機的資料夾路徑 Mapping 到 Container 的資料夾路徑,指令如下
在執行 docker run 指令時,有一個參數是 –net,它可以設定在執行 Docker Container 是要使用哪一種的網路模式,目前所知道的網路模式有 none、container、host、bridge、overlay… 等等的模式,它們是透過使用 Linux 的 libnetwork 所建立出來的網路模式,以下分別說明這些網路模式:
host: container 的網路設定和實體主機使用相同的網路設定,所以 container 裡面也就可以修改實體機器的網路設定,因此使用此模式需要考慮網路安全性上的問題
bridge: Docker 預設就是使用此網路模式,這種網路模式就像是 NAT 的網路模式,例如實體主機的 IP 是 192.168.1.10 它會對應到 Container 裡面的 172.17.0.2,在啟動 Docker 的 service 時會有一個 docker0 的網路卡就是在做此網路的橋接。
overlay: container 之間可以在不同的實體機器上做連線,例如 Host1 有一個 container1,然後 Host2 有一個 container2,container1 就可以使用 overlay 的網路模式和 container2 做網路的連線。