作者 | 于先森2017
責編 | 伍杏玲
出品 | CSDN博客
最近公司新接到一個項目,慣例是通過技術架構、業務需求、用戶量還有以往的經驗大概評估出一份資源配置表格提供給客戶,讓客戶參考采購的服務器資源。但這次客戶根本沒有根據我們提供的參考表格來,而是直接就提供給我們一些高配置的服務器實例,實例數與我們預期的少了很多,但配置相對的提高了很多,本著客戶是上帝的原則,我們只能自己針對服務器做虛擬化。
我為什么選擇用Docker虛擬化服務器?
之前一直是在windows系統上做虛擬機,在linux系統上虛擬化服務器還是第一次,更何況這個Linux系統是沒有圖形界面的。在虛擬化服務器之前我也查詢資料做過很多技術比較,最終選擇使用Docker來虛擬化服務器,具體總結優勢無非以下幾點:
1、Docker創建的容器啟動速度快,秒級啟動。
Docker管理容器操作(start、stop 、rm 、restart等等) 都是以秒或毫秒為單位的。
2、Docker可以基于創建的鏡像進行彈性擴展。
創建容器并且根據自己的需求配置好容器后提交鏡像到倉庫,等到需要擴展容器的時候可拉取鏡像啟動相同的容器。
3、Docker創建的容器較輕量級
我可以在一臺服務器上啟動很多容器,如果只是用到某個服務的話,你無需虛擬整套系統版本。當然本文目的是虛擬出一整套系統的運行環境,所以就另當別論了。
4、Docker開源免費
開源的,免費的,低成本的,這就不用我多說了。
Docker的安裝
Docker的安裝這個其實我不必多說什么,網上一搜一大堆。但是有幾點我需要說明下:
1、Docker存儲數據位置及鏡像存儲位置
默認情況下Docker是將數據存儲在/var/lib/docker路徑下的,如果你系統盤的磁盤空間比較小,那你就需要修改Docker的數據存儲路徑了,可通過如下命令查看:
sudodocker info| grep "Docker Root Dir"
修改方法就是先停掉Docker服務,然后在/etc/docker/路徑下創建一個daemon.json文件,在文件里加入如下文本:
{
"graph": "/home/docker"
}
重啟Docker,再次查看Docker存儲路徑是否已經修改,如果不成功請自行百度查找,修改方法不止這一種。
2、拉取私有倉庫鏡像
這個私有倉庫不是Docker收費版的那個,而是針對自己公司搭建的私有倉庫。當你想拉取私有倉庫鏡像的時候,你需要配置私有倉庫的IP和端口號,目的是讓Docker信任你的私有倉庫。具體步驟還是先關閉Docker服務,然后修改daemon.json文件,如下:
{
"graph": "/home/docker",
"insecure-registries":[ "192.168.10.123:5000"]
}
重啟Docker,此時你就可以拉取你私有倉庫的鏡像了。
Docker容器在不同宿主機間通信
在說這個之前我先大概說下Docker網絡配置,Docker安裝后會自動創建3種網絡:bridge、host、none,這三種網絡模式的詳細講解我就不說了,因為太占篇幅,我就大概講下我的理解吧。如下:
1、bridge模式
我理解就是Docker守護進程啟動時會在宿主機上創建一個docker0虛擬網橋,這個網橋的作用就相當于一個交互機,該宿主機上的所有容器都是通過這個虛擬網橋連接外部網絡的,docker0虛擬網橋的IP就相當于該宿主機上所有容器的默認網關。
當創建一個新容器時Docker會在宿主機上創建一對虛擬網卡veth pair設備,并且將veth pair設備的一端放在新創建的容器中,并命名為eth0(容器的網卡),另一端放在宿主機中,以vethxxx這樣類似的名字命名,并將這個網絡設備加入到docker0網橋中。
該模式是Docker創建容器的默認模式,如果想讓外部網絡訪問到容器中的服務,就是需針對端口做映射,歸根究底它實際是在iptables做了DNAT規則,實現端口轉發功能。本文也是使用的這個模式。
根據我使用這么長時間的經驗來看,這種模式的缺點就是需要事先規劃好容器哪些端口該做映射。網上也有教在容器創建好后給容器增添映射端口,但是有的不靠譜兒,有的則是需要修改Docker生成的配置文件,但是如果像我這種構建的是整套系統運行環境,修改配置后重啟可能有些服務就需要重新配置了,比如集群相關的服務。
2、host模式
這種模式其實就是和宿主機共用一套網路環境,它使用的IP就是宿主機的IP,它使用的端口也是宿主機的端口,網絡的隔離性不好,我沒有使用它的根本原因也正是它的隔離性,因為我所使用的宿主機上是存在兩臺系統運行環境的,或多或少的會出現端口沖突問題。
3、none模式
這種模式下的容器沒有網卡、IP、路由等信息。需要我們自己為Docker容器添加網卡、配置IP等。也就是說它沒有辦法聯網,我至今還沒有用過,可能這樣更安全吧。
以上就是我對Docker安裝后創建的三種網絡模式的理解,還有兩種模式(container模式和user-defined模式)可以自行查找了解。
3.1、不同宿主機間容器通信原理圖
上圖為不同宿主機間容器通信的的原理圖,說實話這張圖在網上都被用爛了,但是沒得辦法,誰讓咱確實是按照這么做的呢,對于上圖的講解我也是直接照搬網上查到的,如下:
1)數據從源容器中發出后,經由所在主機的docker0虛擬網卡轉發到flannel0虛擬網卡,這是個P2P的虛擬網卡,flanneld服務監聽在網卡的另外一端。
2)Flannel通過Etcd服務維護了一張節點間的路由表,在稍后的配置部分我們會介紹其中的內容。
3)源主機的flanneld服務將原本的數據內容UDP封裝后根據自己的路由表投遞給目的節點的flanneld服務,數據到達以后被解包,然后直接進入目的節點的flannel0虛擬網卡,
然后被轉發到目的主機的docker0虛擬網卡,最后就像本機容器通信一下的有docker0路由到達目標容器。
這樣整個數據包的傳遞就完成了,這里需要解釋三個問題:
1)UDP封裝是怎么回事?
在UDP的數據內容部分其實是另一個ICMP(也就是ping命令)的數據包。原始數據是在起始節點的Flannel服務上進行UDP封裝的,投遞到目的節點后就被另一端的Flannel服務
還原成了原始的數據包,兩邊的Docker服務都感覺不到這個過程的存在。
2)為什么每個節點上的Docker會使用不同的IP地址段?
這個事情看起來很詭異,但真相十分簡單。其實只是單純的因為Flannel通過Etcd分配了每個節點可用的IP地址段后,偷偷的修改了Docker的啟動參數。
在運行了Flannel服務的節點上可以查看到Docker服務進程運行參數(ps aux|grep docker|grep “bip”),例如“–bip=182.48.56.1/24”這個參數,它限制了所在節點容器獲得的IP范圍。這個IP范圍是由Flannel自動分配的,由Flannel通過保存在Etcd服務中的記錄確保它們不會重復。
3)為什么在發送節點上的數據會從docker0路由到flannel0虛擬網卡,在目的節點會從flannel0路由到docker0虛擬網卡?
例如現在有一個數據包要從IP為172.17.18.2的容器發到IP為172.17.46.2的容器。根據數據發送節點的路由表,它只與172.17.0.0/16匹配這條記錄匹配,因此數據從docker0出來以后就被投遞到了flannel0。同理在目標節點,由于投遞的地址是一個容器,因此目的地址一定會落在docker0對于的172.17.46.0/24這個記錄上,自然的被投遞到了docker0網卡。
3.2、不同宿主機間容器通信安裝部署
雖然安裝部署方法也是在網上找的,但是網上給出的方法大方向是沒問題的就是一些細節講的還不是很清楚,導致我部署的時候還是出現很多問題。下面我會將我安裝部署的過程和遇到的問題整理到本文中。
3.2.1、宿主機環境準備
我準備了四臺宿主機,如下:
四臺宿主機都需要設置hosts:
[root@master ~] # vim /etc/hosts
192.168.10.1master
192.168.10.1etcd
192.168.10.2slave1
192.168.10.3slave2
192.168.10.4slave3
3.2.2、安裝Etcd
本來想搭建etcd的多主機集群的,但是想了下只是在預生產使用而且只是處在前期搭建狀態還沒有正式使用,所以etcd我只在192.168.10.1服務器上搭建了單個主機的,如果后期出現問題,我會修改為多主機集群。
1、安裝etcd服務
yuminstall etcd -y
2、修改etcd配置文件
[root@master ~] # vim /etc/etcd/etcd.conf
#ETCD_CORS= ""
ETCD_DATA_DIR= "/var/lib/etcd/default.etcd"#數據存放路徑
#ETCD_WAL_DIR= ""
#ETCD_LISTEN_PEER_URLS= "http://localhost:2380"
ETCD_LISTEN_CLIENT_URLS= "http://0.0.0.0:2379,http://0.0.0.0:4001"#監聽客戶端地址
#ETCD_MAX_SNAPSHOTS= "5"
#ETCD_MAX_WALS= "5"
ETCD_NAME= "master"#部署節點的名稱
#ETCD_SNAPSHOT_COUNT= "100000"
#ETCD_HEARTBEAT_INTERVAL= "100"
#ETCD_ELECTION_TIMEOUT= "1000"
#ETCD_QUOTA_BACKEND_BYTES= "0"
#ETCD_MAX_REQUEST_BYTES= "1572864"
#ETCD_GRPC_KEEPALIVE_MIN_TIME= "5s"
#ETCD_GRPC_KEEPALIVE_INTERVAL= "2h0m0s"
#ETCD_GRPC_KEEPALIVE_TIMEOUT= "20s"
#
#[Clustering]
#ETCD_INITIAL_ADVERTISE_PEER_URLS= "http://localhost:2380"
ETCD_ADVERTISE_CLIENT_URLS= "http://etcd:2379,http://etcd:4001"#通知客戶端地址
#ETCD_DISCOVERY= ""
3、啟動etcd服務
[root@master ~] # systemctl start etcd.service
[root@master ~] # systemctl enable etcd.service
4、查看etcd服務是否啟動成功
[root@master ~] # netstat -tnlp | grep -E "4001|2380"
tcp 00127.0.0.1: 23800.0.0.0:* LISTEN 22733/etcd
tcp6 00::: 4001:::* LISTEN 22733/etcd
[root@master ~] # ps -ef | grep etcd
etcd 22733114月 17? 03: 33: 44/usr /bin/etcd --name=master --data-dir=/var/lib/etcd/default.etcd --listen-client-urls=http://0.0.0.0:2379,http:// 0.0.0.0: 4001
root 162335104月 22? 00: 04: 37/usr /bin/flanneld -etcd-endpoints=http://etcd: 2379-etcd-prefix=/atomic.io/network
root 333684333652019: 58pts/ 200: 00: 00vi /etc/etcd/etcd.conf
root 334263333652020: 00pts/ 200: 00: 00vi /etc/etcd/etcd.conf
root 338219333652020: 14pts/ 200: 00: 00grep --color=auto etcd
[root@master ~] # etcdctl -C http://etcd:4001 cluster-health
member 8e9e05c52164694d ishealthy: got healthy result fromhttp: //etcd: 2379
cluster ishealthy
[root@master ~] # etcdctl -C http://etcd:2379 cluster-health
member 8e9e05c52164694d ishealthy: got healthy result fromhttp: //etcd: 2379
cluster ishealthy
[root@master ~] #
5、在etcd中配置flannel需要用到的鍵值
[root@master ~] # etcdctl mk /atomic.io/network/config '{ "Network": "172.18.0.0/16"}'
{ "Network": "172.18.0.0/16"}
3.2.3、安裝Flannel
flannel是所有宿主機需要安裝的中間件,而且前文中提到的hosts文件一定要設置好。
1、安裝flannel服務
yuminstall flannel -y
2、修改flannel配置文件
[root@master ~] # vim /etc/sysconfig/flanneld
# Flanneld configuration options
# etcd url location. Point this to the server where etcd runs
FLANNEL_ETCD_ENDPOINTS= "http://etcd:2379"#etcd客戶端端口
# etcd config key. This is the configuration key that flannel queries
# For address range assignment
FLANNEL_ETCD_PREFIX= "/atomic.io/network"#這個參數的值需要是etcd保存的key值,不然flannel啟動不了
# Any additional options that you want to pass
#FLANNEL_OPTIONS=""
flanneld配置文件中的FLANNEL_ETCD_PREFIX參數與上文中保存在etcd中的一個鍵值是相對應的,但要注意FLANNEL_ETCD_PREFIX參數的值沒有后邊的/config。
3、啟動flanneld服務
[root@master ~] # systemctl start flanneld.service
[root@master ~] # systemctl enable flanneld.service
4、查看flanneld服務是否啟動成功
[root@master ~] # ps -ef|grep flanneld
root 162335104月 22? 00: 04: 38/usr/bin/flanneld -etcd-endpoints=http: //etcd: 2379-etcd-prefix= /atomic.io/network
root 345092333652020: 37pts/ 200: 00: 00vim /etc/sysconfig/flanneld
root 345496333652020: 39pts/ 200: 00: 00vim /etc/sysconfig/flanneld
root 345545333652020: 39pts/ 200: 00: 00vim /etc/sysconfig/flanneld
root 347078333652020: 44pts/ 200: 00: 00vim /etc/sysconfig/flanneld
root 350147333652020: 54pts/ 200: 00: 00grep--color=auto flanneld
[root@master ~] # ifconfig flannel0
flannel 0: flags= 4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1472
inet 172.18. 92.0netmask 255.255. 0. 0destination 172.18. 92.0
inet6 fe8 0:: 244d:d95c:a79f:af2d prefixlen 64scopeid 0x20< link>
unspec 00- 00- 00- 00- 00- 00- 00- 00- 00- 00- 00- 00- 00- 00- 00- 00txqueuelen 500(UNSPEC)
RX packets 2691026bytes 142959067( 136.3MiB)
RX errors 0dropped 0overruns 0frame 0
TX packets 2690704bytes 152477868( 145.4MiB)
TX errors 0dropped 0overruns 0carrier 0collisions 0
此時可看到flannel生成的flannel0網卡的IP是在etcd保存的網段內的,說明flannel網絡配置完成。
3.2.4、配置docker0虛擬網橋
安裝啟動flanneld后重啟Docker服務,查看Docker服務生成的docker0網橋IP是否已經位于flanneld生成flannel0網卡的網段之中,比如flannel0網卡的IP是:172.18.92.0,docker0的IP是:172.18.92.1,則配置成功。如果IP地址的前三段有一段不同,則說明需要重新對docker0虛擬網橋進行配置,配置方法如下:
1、停掉Docker服務,修改docker.service配置文件
[root@master ~] # systemctl stop docker
[root@master ~] # vim /usr/lib/systemd/system/docker.service
ExecStart= /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip= 172.18. 92.1/ 24
如上就是需要在docker.service文件中的ExecStart參數后添加–bip=172.18.92.1/24,bip的值請查看/run/flannel/subnet.env文件的FLANNEL_SUBNET值,這兩個需要保持一致。
2、重啟Docker
[root@master ~] # systemctl daemon-reload
[root@master ~] # systemctl restart docker
3、docker0是否配置成功
[root@master ~] # ifconfig flannel0
flannel0:flags= 4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1472
inet 172.18. 92.0netmask 255.255. 0. 0destination 172.18. 92.0
inet6 fe80:: 244d:d95c:a79f:af2d prefixlen 64scopeid 0x20<link>
unspec 00- 00- 00- 00- 00- 00- 00- 00- 00- 00- 00- 00- 00- 00- 00- 00txqueuelen 500(UNSPEC)
RX packets 2701666bytes 143511551( 136.8MiB)
RX errors 0dropped 0overruns 0frame 0
TX packets 2701343bytes 153069980( 145.9MiB)
TX errors 0dropped 0overruns 0carrier 0collisions 0
[root@master ~] # ifconfig docker0
docker0:flags= 4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.18. 92.1netmask 255.255. 255.0broadcast 172.18. 92.255
inet6 fe80:: 42:cff:fe75:d72prefixlen 64scopeid 0x20<link>
ether 02:42:0 c:75:0 d:72txqueuelen 0(Ethernet)
RX packets 4010425bytes 230843638( 220.1MiB)
RX errors 0dropped 0overruns 0frame 0
TX packets 3057671bytes 995135672( 949.0MiB)
TX errors 0dropped 0overruns 0carrier 0collisions 0
如上docker0處于flannel0的網段內,說明配置已經成功。
3.2.5、驗證宿主機間容器是否通信
如果以上步驟都已配置成功,此時就需要驗證不通宿主機間容器是否通信了,驗證方法就是在每個宿主機創建個容器,然后在容器中ping其他宿主機中容器的Ip,如果能夠ping通,則說明已經完成。如果Ping不通也不要驚慌,因為可能是底層的iptables造成的,所以解決辦法是在各宿主機上執行下面操作:
[root@master ~] # iptables -P INPUT ACCEPT
[root@master ~] # iptables -P FORWARD ACCEPT
[root@master ~] # iptables -F
[root@master ~] # iptables -L -n
以上只完成后再次測試容器間是否能夠相互ping通,還是不可以的話就需要排查是否那個環節疏忽出現問題了。docker通過Flannel可以實現各容器間的相互通信,即宿主機和容器,容器和容器之間都能相互通信。
制作centos系統版本容器
1、拉取centos:7.6.1810系統版本的鏡像
[root@master ~] # docker pull centos:7.6.1810
2、創建容器
[root@master ~] # docker run -itd --name pre-centos --privileged=true -p 10022:22 centos:7.6.1810 init
我對該命令中的參數具體講解下:
-i:以交互模式運行容器,通常與 -t 同時使用。
-t:為容器重新分配一個偽輸入終端,通常與 -i 同時使用。
-d:后臺運行容器,并返回容器ID,如果不加這個參數,當退出容器時,這個容器也就停止了。
–privileged:默認是false,我們這里改成了true,使用該參數容器中的root擁有真正的root權限,否則容器的root用戶只是宿主機的一個普通用戶權限,有些命令如:systemctl、service是使用不了的。
-p:就是映射端口的作用
還有一個問題需要注意,就是該命令后的init,加上它賦值給容器真正的root權限才會生效,如果使用/bin/bash是不會生效的。
3、進入創建好的容器
[root@master ~] # docker exec -it 1fc31e49daxc bash
1fc31e49daxc 參數為新創建容器的CONTAINER ID。
4、安裝啟動ssh
[ root@1fc31e49daxc ~] # yum -y install openssh-server
[ root@1fc31e49daxc ~] # systemctl start sshd
容器中安裝配置ssh,就是希望外部工具能夠通過容器映射宿主機的10022端口直接訪問到容器里。
5、修改ssh配置文件
[root@ 1fc31e49daxc ~] # vi /etc/ssh/sshd_config
#配置信息去掉如下注釋
Port 22ListenAddress 0.0.0.0
ListenAddress ::
permitrootlogin yes
UsePAM yes改為 UsePAM no
GSSAPICleanupCredentials no改為 GSSAPICleanupCredentials yes
UsePrivilegeSeparation sandbox 改為 UsePrivilegeSeparation no
6、重啟ssh
[ root@1fc31e49daxc ~] # /usr/sbin/sshd -D
7、設置linux容器的密碼
[ root@1fc31e49daxc ~] # passwd root
8、退出容器并將容器提交成鏡像
[ root@1fc31e49daxc ~] # exit
[ root@master ~] # docker commit 1fc31e49daxc pre-centos:1.0
9、將鏡像打成標簽提交私有倉庫
[root@master ~] # docker tag 8a1960ed7c4c 192.168.12.10:5000/yuliang/pre-centos:1.0
[root@master ~] # docker push 8a1960ed7c4c
8a1960ed7c4c 為IMAGE ID,修改標簽后的鏡像與提交的鏡像IMAGE ID是一樣的。
10、拉取私有倉庫鏡像
[root@slave1 ~] # docker pull 192.168.12.10:5000/yuliang/pre-centos:1.0
11、創建新的容器
[root@slave1 ~] # docker run -itd --name pre-centos --privileged=true -m 30G -p 10022:22 -p 3357:3306 -p 8024:8024 -p 8025:8025 192.168.12.10:5000/yuliang/pre-centos:1.0 /usr/sbin/init
其中有一個新的參數-m需要講一下,其實它就是限制容器使用的內存,默認情況下容器使用的資源是根據宿主機來定的,宿主機有多少資源它就能夠用多少資源。容器的磁盤空間除外,容器的磁盤空間是根據Docker存儲數據路徑所在宿主機的那個磁盤大小定的,也就是說Docker存儲數據路徑所在磁盤有100G,容器也只能夠使用100G的磁盤。而內存和CPU在默認情況下宿主機有多少資源它就能夠用多少資源。這個容器我使用了-m來限制容器只能使用30G內存。
(注:再次提醒事先規劃好容器使用的端口在創建容器,如果容器已經創建成功后想添加端口請查看這篇文章:為已創建的容器添加映射端口)
12、測試容器是否正常運行
[root@slave1 ~] # docker ps
[root@slave1 ~] # docker exec -it a38321832cfd bash
13、查看容器信息
[root@slave1 ~] # docker inspect a38321832cfd
這條命令執行后顯示的信息就是該a38321832cfd容器構建時候的全部信息,包括IP、端口映射等等。
14、訪問容器
1、如果是在做過容器間通信的宿主機上連接訪問可通過以下命令:
[root@master ~]# sshroot@ 172. 18. 91. 2
注意使用的容器的22端口。
2、如果是在沒有做過容器間通信的服務器上連接訪問則需要通過以下命令:
[root@ecs-12 ~]# ssh-p10022 root@ 192. 168. 10. 2
3、如果是使用外部工具訪問容器,需要用到也是宿主機的10022端口和宿主機的IP。
上文參考:
總結
以上關于如何做不同宿主機間容器通信和使用Docker創建虛擬機服務器我已經講解的很清楚了,文中有些我是在網上找來的也添加了出處,在網上找來的內容我也有實際認認真真的研究過并且加以改進我才敢在我們的預生產環境使用。因為現在還沒到真正的測試實驗階段,所以我不敢打包票說這些內容一定沒有問題。
后續我會將遇到的問題整理進這篇文章的,如果我沒有添加則說明確實沒有問題了。看到這篇文章的人發現文中有問題可隨時給我留言。最后說一句話,有些事情看著很容易,實際做起來你會發現也很容易,但得需要你去做啊。
版權聲明:本文為CSDN博主「于先森2017」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。