前言
Docker 是一個開源項目侥啤,誕生于 2013 年初当叭,最初是 dotCloud 公司內(nèi)部的一個業(yè)余項目茬故。它基于 Google 公司推出的 Go 語言實現(xiàn)。 項目后來加入了 Linux 基金會蚁鳖,遵從了 Apache 2.0 協(xié)議磺芭,項目代碼在 GitHub 上進行維護。
Docker 自開源后受到廣泛的關(guān)注和討論醉箕,以至于 dotCloud 公司后來都改名為 Docker Inc钾腺。Redhat 已經(jīng)在其 RHEL6.5 中集中支持 Docker;Google 也在其 PaaS 產(chǎn)品中廣泛應(yīng)用琅攘。
Docker 項目的目標(biāo)是實現(xiàn)輕量級的操作系統(tǒng)虛擬化解決方案垮庐。 Docker 的基礎(chǔ)是 Linux 容器(LXC)等技術(shù)。在 LXC 的基礎(chǔ)上 Docker 進行了進一步的封裝坞琴,讓用戶不需要去關(guān)心容器的管理哨查,使得操作更為簡便。用戶操作 Docker 的容器就像操作一個快速輕量級的虛擬機一樣簡單剧辐。
下面兩張圖比較了傳統(tǒng)虛擬機和docker之間的區(qū)別
從而我們可以看出傳統(tǒng)虛擬機是在硬件層面實現(xiàn)的寒亥,而docker是在操作系統(tǒng)層面上實現(xiàn)的虛擬化
p.s.:Hypervisor是一種運行在物理服務(wù)器和操作系統(tǒng)之間的中間軟件層,可允許多個操作系統(tǒng)和應(yīng)用共享一套基礎(chǔ)物理硬件荧关,因此也可以看作是虛擬環(huán)境中的“元”操作系統(tǒng)溉奕,它可以協(xié)調(diào)訪問服務(wù)器上的所有物理設(shè)備和虛擬機,也叫虛擬機監(jiān)視器(Virtual Machine Monitor)忍啤。Hypervisor是所有虛擬化技術(shù)的核心加勤。非中斷地支持多工作負載遷移的能力是Hypervisor的基本功能。當(dāng)服務(wù)器啟動并執(zhí)行Hypervisor時同波,它會給每一臺虛擬機分配適量的內(nèi)存鳄梅、CPU、網(wǎng)絡(luò)和磁盤未檩,并加載所有虛擬機的客戶操作系統(tǒng)戴尸。
現(xiàn)在項目一般為單點登錄或者是分布式,而分布式能想到微服務(wù)冤狡,所以如果把這種思想應(yīng)用到容器部署中則會有基于單容器部署(類似單點登錄)和多容器部署(類似微服務(wù))兩種方式孙蒙,多容器部署即把mysql、rabbitMq悲雳、redis等依賴組件和spring boot服務(wù)分開成多個容器來部署的方式挎峦;單容器部署即把MySQL等其他組件和spirng boot應(yīng)用放在同一容器的部署方式。
多容器部署的方式是目前主流的方式合瓢,因為具有以下優(yōu)勢:
- 方便橫向擴展浑测;
- 服務(wù)可用性高,不會因為一個容器服務(wù)掛了而導(dǎo)致所有服務(wù)都不能用;
- 單個容器不會太臃腫迁央、資源消耗相對較兄澜场;
- 部署方便岖圈。
多容器的部署方式又有基于docker命令和基于docker-compose命令兩種方式讹语。這里首先要再介紹下docker compose。
Docker Compose 是Docker官方編排(Orchestration)項目之一蜂科,負責(zé)快速在集群中部署分布式應(yīng)用顽决。比較直觀的感受是多個容器可以通過一個配置來啟動,從而簡化了部署過程导匣,我們也可以通過一個配置文件來查看部署的命令等等才菠。
下面我就介紹基于docker run等docker命令和基于docker compose兩種部署方式
e.g:本文中前端采用pm2工具部署,后端采用spring boot + mysql + redis + rabbitmq
基于docker命令部署
后端Spring boot及依賴服務(wù)部署
首先Spring Boot應(yīng)用依賴于Mysql贡定、redis和RabbitMQ服務(wù)赋访,所以我們先把這三個服務(wù)部署好。
在安裝部署前我們可以搜索要安裝的服務(wù)有哪些鏡像缓待,可以選擇合適我們的蚓耽。
docker search 鏡像名
例如要搜索mysql的鏡像就可以用命令(其他服務(wù)同理)
docker search mysql
MySQL服務(wù)部署
我采用了鏡像搜索結(jié)果中的第一個鏡像
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relati... 7708 [OK]
執(zhí)行鏡像拉去命令
docker pull mysql
使用該命令會去拉取tag為latest的mysql鏡像,使用以下命令可以查看本地存在的所有鏡像旋炒,我們就可看到剛才下載的mysql鏡像了步悠。
docker images
使用啟動鏡像的命令:
docker run --name test-mysql --restart=always -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql --lower_case_table_names=1 --default-authentication-plugin=mysql_native_password
p.s:命令詳解
--name:給容器命名
-
--restart:容器重啟策略
- no,默認策略瘫镇,在容器退出時不重啟容器
- on-failure鼎兽,在容器非正常退出時(退出狀態(tài)非0),才會重啟容器
- on-failure:3铣除,在容器非正常退出時重啟容器接奈,最多重啟3次
- always,在容器退出時總是重啟容器
- unless-stopped通孽,在容器退出時總是重啟容器,但是不考慮在Docker守護進程啟動時就已經(jīng)停止了的容器
-p:端口映射睁壁,映射邏輯為主機端口:容器端口
-e:參數(shù)設(shè)置背苦,這里的MYSQL_ROOT_PASSWORD就是設(shè)置賬號名為root的賬戶的密碼
-d:后臺運行容器
mysql:要運行的鏡像名
--lower_case_table_names=1:設(shè)置不區(qū)分表名大小寫,不然可能會在spring boot應(yīng)用時報表不存的錯誤(實際創(chuàng)建的數(shù)據(jù)庫和表為:test.user潘明,報錯提示為test.USER is not exist)
--default-authentication-plugin=mysql_native_password:mysql版本為8.0以上時需要行剂,因為8.0和5.7的密碼加密機制不同,如果本地navicat版本不支持新的加密機制(ERROR 2059 (HY000): Authentication plugin 'caching_sha2_password' cannot be loaded)則要加上這條命令钳降;如果不加的話也可以通過后續(xù)密碼的方式來解決厚宰。解決方法如下:1.執(zhí)行命令:docker exec -it 容器id /bin/bash;2.再執(zhí)行:mysql -h 127.0.0.1 -P 3306 -u root -p,輸入密碼進去mysql铲觉;3.修改密碼:ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root';
p.s:
- 第三步中的BY 'root'澈蝙,root為要設(shè)置的新密碼。
- docker exec -it表示開啟交互模式的終端(-it=-i -t)
- /bin/bash表示可以執(zhí)行一些簡單的shell命令
在執(zhí)行完以上操作后就可以用Navicat等工具鏈接數(shù)據(jù)庫測試是否搭建成功撵幽。
Redis服務(wù)部署
搜索和下載鏡像的部署同MySQL中一樣灯荧,本文采用的redis鏡像為:
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
redis Redis is an open source key-value store th... 6431 [OK]
執(zhí)行命令啟動服務(wù)
docker run -d --name test-redis -p 6379:6379 redis --requirepass 'mypassword'
如果要開啟redis的持久化則加上 --appendonly yes
完成命令如下:
docker run -d --name test-redis -p 6379:6379 redis --requirepass 'mypassword' --appendonly yes
如果不加--appendonly yes則默認開啟redis的RDB模式,如果加了則開啟AOF模式盐杂。
redis服務(wù)測試:
docker exec -it 容器id redis-cli -h 127.0.0.1 -p 6379
進入redis后驗證密碼的命令為:
auth mypassword
RabbitMQ服務(wù)部署
本文拉取的rabbitmq的鏡像為:(rabbitmq:management)
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
rabbitmq RabbitMQ is an open source multi-protocol ... 2445 [OK]
運行服務(wù)命令:
docker run -d --hostname localhost --name test-rabbit -p 15672:15672 -p 5672:5672 rabbitmq:management
--hostname:指定容器主機名稱
這里用了兩次-p的端口映射是因為5672是給服務(wù)用的端口逗载。15672是web端訪問的接口
如果要在啟動時同時設(shè)置用戶和密碼可使用一下命令
docker run -d --hostname localhost --name test-rabbit -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin -p 15672:15672 -p 5672:5672 rabbitmq:management
啟動服務(wù)后檢查是否可以通過訪問ip:15672打開web管理頁面(使用的鏡像如果是rabbitmq:latest則無法打開,如果是rabbitmq:management則可以打開)链烈,如果打不開則是因為rabbitmq默認不開啟web頁面厉斟,需要進去容器中設(shè)置。執(zhí)行命令:
docker exec -it 容器id /bin/bash
在進入容器后執(zhí)行:
rabbitmq-plugins enable rabbitmq_management
我們再訪問web頁面就發(fā)現(xiàn)可以打開了强衡。
Spring Boot服務(wù)部署
在部署完其他的組件后終于可以部署我們的應(yīng)用了擦秽,而整體的思路就是把我們的應(yīng)用的jar文件變成鏡像文件,然后再運行即可食侮。所以首先我們需要把應(yīng)用打包成jar文件号涯,拷貝到服務(wù)器上一個目錄下,本文中拷貝到了/opt/test/jar文件夾下锯七,然后在該文件夾下再用命令vi Dockerfile創(chuàng)建文件链快。
#指定基礎(chǔ)鏡像,格式為:FROM image:tag
FROM java
#維護者信息
MAINTAINER TEST
#添加要加入的文件眉尸,與COPY命令的性質(zhì)基本一致域蜗,但是ADD更強大
#可添加源路徑,可自動解壓壓縮包噪猾,但解壓功能和指定目標(biāo)路徑不可同時使用
#該命令在使用docker run -v時可不用霉祸,在后續(xù)有介紹
ADD spring-boot-test.jar /opt/test/test.jar
#add命令會把config下的所有文件拷貝到容器中的/opt/test/config下,此條代碼只用作添加文件夾的講解示范,
ADD config /opt/test/config/
#用于指定在容器啟動時要執(zhí)行的命令
CMD java -jar /opt/test.jar
#為構(gòu)建鏡像設(shè)置監(jiān)聽端口袱蜡,使容器在運行時監(jiān)聽
EXPOSE 8082
以上就是創(chuàng)建一個簡單的Dockerfile的示例丝蹭。
然后運行命令:
docker build -t my-test-image .
- -t:給鏡像命名
- 最后的點表示使用當(dāng)前上下文中的dockerfile文件
構(gòu)建好了可以用以下命令查看是否有自己的鏡像了
docker images
有我們的鏡像后就可以運行了。
docker run -d -p 8082:8082 --name my-spring-boot my-test-image
e.g.(推薦)
可以在docker run的時候加入-v 來映射數(shù)據(jù)卷坪蚁,這樣的話在后續(xù)版本更新中可方便地替換jar文件奔穿。
docker run -d -p 8082:8082 --name my-spring-boot -v jar:/opt/test
這條命令中 -v后的參數(shù)的意思為:把本機的當(dāng)前目錄的jar文件夾映射到容器中的/opt/test文件夾,這樣每次更新只需更換test.jar即可(使用數(shù)據(jù)卷的話可在Dockerfile中把ADD spring-boot-test.jar /opt/test/test.jar這行命令去掉)
使用以下命令可查看當(dāng)前運行的鏡像
docker ps
如果要查看運行過的所有鏡像(包括以前運行過敏晤,現(xiàn)在停止的)
docker ps -a
如果啟動失敗了可以通過以下幾條命令查看容器日志排查問題
docker logs [OPTIONS] CONTAINER
Options:
--details 顯示更多的信息
-f, --follow 跟蹤實時日志
--since string 顯示自某個timestamp之后的日志贱田,或相對時間,如42m(即42分鐘)
--tail string 從日志末尾顯示多少行日志嘴脾, 默認是all
-t, --timestamps 顯示時間戳
--until string 顯示自某個timestamp之前的日志男摧,或相對時間,如42m(即42分鐘)
前端pm2部署
1.首先把項目文件發(fā)布到服務(wù)器上,本例中放到了/opt/frontend/file下
2.拉取node鏡像耗拓,本例中用的node鏡像為:
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
node Node.js is a JavaScript-based platform for... 6935 [OK]
3.使用vi Dockerfile創(chuàng)建文件拇颅,文件內(nèi)容如下:
#使用的基礎(chǔ)鏡像
FROM node:latest
#作者信息
MAINTAINER test
#把file文件夾下的所有文件添加到容器的/opt/frontend下
ADD file /opt/frontend/
#在鏡像的構(gòu)建過程中執(zhí)行特定的命令并生成一個中間鏡像,node的鏡像中沒有pm2帆离,所以在此安裝
RUN npm install -g pm2
#指定工作路徑蔬蕊,之后的命令將在此路徑上運行
WORKDIR /opt/frontend
#因為本例中不會自動生成日志文件和文件夾所以在這創(chuàng)建,如果自己的項目不需要的可以去掉這里的命令
RUN mkdir logs
RUN touch logs/app.log
#修改腳本的權(quán)限哥谷,不然會報沒有權(quán)限的錯誤
RUN chmod 775 frontend-start.sh
#npm安裝
RUN npm install
#暴露前端4010端口(根據(jù)自己前端服務(wù)的端口修改)
EXPOSE 4010
#執(zhí)行腳本
CMD /opt/frontend/frontend-start.sh
e.g:因為CMD命令是只有最后一個才生效岸夯,而我們要執(zhí)行的命令又不止一條,所以采用了運行腳本文件的方式來運行
腳本文件frontend-start.sh內(nèi)容如下:
#pm2部署項目
pm2 start /opt/frontend/pm2.json
#持續(xù)監(jiān)控日志们妥,讓容器不退出
tail -f /opt/frontend/logs/app.log
4.在編寫完這些文件后就可以開始構(gòu)建鏡像
docker build -t test-frontend .
最后的點表示使用當(dāng)前上下文中的dockerfile文件
5.使用docker images命令查看我們構(gòu)建的鏡像
運行鏡像的命令
docker build -d -p 4010:4010 --name test-frontend test-frontend:latest
6.運行之后我們通過docker ps命令查看容器是否在運行猜扮,如果在運行了就可在本地通過瀏覽器訪問地址來打開頁面:http://服務(wù)器ip:4010
7.如果運行有錯誤可通過docker logs 容器id來查看日志解決問題
基于docker-compose部署
首先我介紹一下本例子的目錄結(jié)構(gòu)
-docker-compose.yml
-fontend
-Dockerfile
-files(前端項目文件,已包含pm2.json)
-backend
-Dockerfile
-test.jar
-mysql
-Dockerfile
-db
-sql(要初始化數(shù)據(jù)庫所需要的sql)
前后端的Dockerfile在前文中已經(jīng)介紹监婶,這里主要相比前文做一些差異化介紹旅赢,差一點就在于docker-compose.yml文件和mysql的Dockerfile
mysql的Dockerfile的內(nèi)容如下:
#使用mysql8.0在后續(xù)的sql自動執(zhí)行中會有問題,所以這里采用mysql5.7
FROM mysql:5.7
MAINTAINER test-mysql-compose
#把sql
ADD sql /docker-entrypoint-initdb.d
編寫該Dockerfile的目的主要是把要初始化mysql數(shù)據(jù)庫的sql文件添加入容器中惑惶,把我們想要自動執(zhí)行的sh文件或sql文件放入/docker-entrypoint-initdb.d中即可煮盼,在容器初始化時就會自動執(zhí)行(原理是在容器中的/docker-enetrypoint.sh文件,容器啟動時會去執(zhí)行該文件带污,該文件又會去執(zhí)行/docker-entrypoint-initdb.d中的sh和sql文件)
e.g.
這里有兩個需要特別注意的問題
- 在mysql8.0中如果在docker-compose中添加了volumn的映射就不會再去執(zhí)行docker-entrypoint.sh文件僵控,而5.7版本沒有這個問題。我暫沒有找到解決辦法鱼冀,所以這里就采用了5.7版本报破。
- 我在添加了sql文件,執(zhí)行mysql鏡像后出現(xiàn)連不上mysql的問題千绪,報的unknow server的錯誤充易,過了十多分鐘后才能正常臉上。經(jīng)過排查才發(fā)現(xiàn)是因為sql文件太大導(dǎo)致沒有導(dǎo)入完(我的運行了16個SQL文件大概共15.5MB荸型,用了20分鐘左右)盹靴。這樣的問題當(dāng)然有主機性能等因素影響,所以建議初始化的sql文件盡量要小瑞妇。
接下來就是最重要的docker-compose.yml文件的介紹
#docker-compose的版本
version: '3'
#定義服務(wù)
services:
#服務(wù)名稱稿静,可隨意定義
backend:
build:
#dockerfile的路徑
context: backend
#dockerfile的名稱
dockerfile: Dockerfile
#相當(dāng)于docker run -v的作用
volumes:
- "./jar:/opt/test"
#容器名稱
container_name: test-backend-compose
#該服務(wù)依賴的其他服務(wù),該配置選項可修改啟動順序
depends_on:
- mysql
- redis
- rabbitmq
ports:
- "8082:8082"
frontend:
build:
context: frontend
dockerfile: Dockerfile
ports:
- "4010:4010"
container_name: test-frontend-compose
mysql:
build:
context: mysql
dockerfile: Dockerfile
ports:
- "3306:3306"
#相當(dāng)于docker run命令中的-e
environment:
MYSQL_ROOT_PASSWORD: root
#初始化的數(shù)據(jù)庫名稱
MYSQL_DATABASE: test
container_name: test-mysql-compose
restart: always
#數(shù)據(jù)卷映射關(guān)系踪宠,把本機的./mysql/db目錄映射到容器中的/var/lib/mysql
volumes:
- "./mysql/db/:/var/lib/mysql"
#該選項中的命令會覆蓋Dockfile中的CMD中的命令.lower_case_table_names參數(shù)是為了表名不區(qū)分大小寫,default-authentication-plugin是8.0中密碼加密策略不同帶來的鏈接問題妈嘹,如果不用8.0可不加此選項
command: mysqld --lower_case_table_names=1 --default-authentication-plugin=mysql_native_password
redis:
image: redis
ports:
- "6379:6379"
container_name: test-redis-compose
restart: always
#啟動redis服務(wù)并添加密碼為:123456,并開啟redis的持久化
command: redis-server --requirepass 123456 --appendonly yes
rabbitmq:
image: rabbitmq:management
ports:
- "5672:5672"
- "15672:15672"
container_name: test-rabbitmq-compose
environment:
#rabbitmq的初始用戶名
RABBITMQ_DEFAULT_USER: admin
#rabbitmq的初始密碼
RABBITMQ_DEFAULT_PASS: 123456
#指定使用的網(wǎng)絡(luò)柳琢,此處是使用已經(jīng)提前創(chuàng)建好的自定義網(wǎng)絡(luò)
#網(wǎng)絡(luò)創(chuàng)建命令:docker network create -d bridge --subnet 172.50.0.0/16 cooperationassociation
#--subnet指定網(wǎng)段 -d指定連接方式,最后的cooperationassociation為網(wǎng)絡(luò)名稱
#使用新的指定網(wǎng)絡(luò)是為了防止網(wǎng)段占用完,這樣會導(dǎo)致啟動容器時XShell會自動退出柬脸,且本地用不了訪問不了服務(wù)(服務(wù)器已有大量連接時可能會出現(xiàn))
#查看網(wǎng)段占用情況的命令:route -n
networks:
default:
external:
name: cooperationassociation
編寫文件后使用以下命令即可運行
#-d表示后臺運行
docker-compose up -d
docker-compose還有以下常用命令
#停止運行并移除容器
docker-compose down
#啟動單個服務(wù)
docker-compose up -d 服務(wù)名
#查看當(dāng)前運行的服務(wù)
docker-compose ps
#構(gòu)建鏡像他去,--no-cache表示不用緩存,否則在重新編輯Dockerfile后再build可能會直接使用緩存而導(dǎo)致新編輯內(nèi)容不生效
docker-compose build --no-cache
#查看鏡像
docker-compose images
#查看日志
docker-compose logs
#啟動/停止服務(wù)
docker-compose start/stop 服務(wù)名
#拉取鏡像
docker-compose pull 鏡像名
以上只是一些最常用的命令倒堕,我們也可以看出常用的docker命令在docker-compose中也可使用灾测。