動手學Docker-第三彈-Docker網絡
完整項目請查看Github:鏈接
或通過gitbook在線查看: 鏈接
Docker網絡
Docker單機網絡
關於網絡基礎知識大家請系統學習計算機網絡相關內容。
這裏介紹兩個幾個常用命令:
- ping:查看指定IP是否可達
ping 192.168.0.1
。 - telnet:查看服務是否可用
telnet 192.168.0.1 80
,有的地址不可以ping但是可以用telnet。 - curl:用來請求 Web 服務器。它的名字就是客戶端(client)的 URL 工具的意思。
- wget:一個下載文件的工具。
- ip a:顯示IP地址。
查看docker的網絡:
docker network ls
可以看到在docker中有三種網絡:
默認情況下容器使用的是橋接也就是Bridge Network,之後我們啓動一個容器並查看網絡具體內容
docker run -d --name test1 busybox /bin/sh -c "while true;do sleep 3600;done"
docker inspect 0b464e45177b(改成你查看到的NETWORK ID)
在network的具體細節內我們可以看到containers中包含了我們剛纔創建的容器
可以看到我們當前的容器是連接到了bridge的網絡中。在我們的主機和容器之間會創建一對vethnet以便於容器和主機之間相互通信,在主機的終端上我們可以直接ping通容器的ip地址。
這時我們再創建一個容器
docker run -d --name test2 busybox /bin/sh -c "while true;do sleep 3600;done"
再次查看network的具體內容
同時test2也會創建一堆vethnet,test1和test2的vethnet端口會都連接在一個bridge上,所以他們兩個之間可以相互ping通。
在已經知道了兩個容器之間可以相互訪問的情況下,我們現在需要實現這樣一個需求:
- 首先啓動另一個容器db,在這個容器上運行數據庫服務
- 同時啓動一個容器web,這個容器中我們可以運行一個用戶註冊服務
- 用戶點擊註冊後,web容器將數據存儲到dbrongqi中
以上的這個操作必然要涉及兩個容器的網絡鏈接,我們知道可以通過IP地址相互ping通,但是在大規模集羣的情況下不可能手動的去指定IP,這個時候我們如何讓這兩個容器知道對方的存在呢?
我們可以在創建容器時使用--link
參數,來制定我們創建的這個容器要連接到哪個容器上。
docker run -d --name test2 --link test1 busybox /bin/sh -c "while true;do sleep 3600;done"
之後我們進入test2中,ping test1
的IP地址和test1都可以ping通。也就是我們在使用--link
時是創建的DNS服務,將test1映射到172.17.0.2上。
我們也可以手動創建一個network,在創建容器時將容器連接到我們自己創建的network上,此時如果我們在自建的網絡上創建兩個容器,他們兩個之間是默認link
好的。
Docker端口映射
我們啓動一個容器裏面一定會運行一些服務,但是這些服務我們如何才能讓外界訪問到呢?首先肯定是連接好網絡,這之前我們已經說過了。另一個重要的就是端口映射。
假如說我們在服務器上啓動nginx的服務,他默認是通過80端口來訪問的,但是我們如何通過訪問服務器的80端口來默認的訪問到容器中的nginx服務呢?我們在運行容器時可以使用這個命令:
docker run --name web -d -p 80:80 nginx
我們通過-p參數來將容器的80端口映射到服務器的80端口上,這樣我們訪問服務器的80端口時就會直接請求nginx服務。
我們容器的IP地址:
Linux服務器的IP地址分別是:
然後我們訪問Linux服務器的80端口:
可以看到確實是可以成功映射的。
flask-redis實戰
我們這個應用是使用flask搭建一個應用,這個應用是我們每訪問一次網址就會在redis的數據庫上加1。
首先我們創建一個啓動redis服務的容器
docker run -d --name redis redis
之後我們編寫一下python文件,名字叫做app.py
from flask import Flask
from redis import Redis
import os
import socket
app = Flask(__name__)
redis = Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379)
@app.route('/')
def hello():
redis.incr('hits')
return 'Hello Container World! I have been seen %s times and my hostname is %s.\n' % (redis.get('hits'),socket.gethostname())
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)
在創建Dockerfile,並編輯裏面的內容
FROM python:2.7
COPY . /app
WORKDIR /app
RUN pip install flask redis
EXPOSE 5000
CMD [ "python", "app.py" ]
然後根據Dockerfile創建我們自己的鏡像
docker build -t su/flask-redis .
最後將我們自己創建的鏡像加載成容器對外提供服務,並且將容器的5000端口映射到服務器的5000端口
docker run -d --link redis -p 5000:5000 --name flask-redis -e REDIS_HOST=redis su/flask-redis
我們來看一下效果,首次訪問
再訪問一次看一下效果
可以看到我們已經實現了多容器應用的部署💯。
Docker多機網絡
剛纔我們已經成功的實現了flask-redis應用程序,但是還存在一個問題,我們的服務可能是訪問量很大的一個服務,這時需要我們將redis和flask部署到不同的服務器上,我們怎麼才能讓這兩個部署在不同服務器上的容器相互通信呢?
兩個容器之間數據的傳遞使用的技術是VXLAN,他是一個overlay網絡的實現,更多內容可以參考:關於VLAN和VXLAN的理解。
想要實現兩個容器進行通信我們需要一個技術來支持就是etcd,關於etcd的更多內容大家可以查看:Etcd 使用入門,高可用分佈式存儲 etcd 的實現原理。etcd 的官方將它定位成一個可信賴的分佈式鍵值存儲服務,它能夠爲整個分佈式集羣存儲一些關鍵數據,協助分佈式集羣的正常運轉。也就是我們的兩臺服務器要分別在etcd服務上進行註冊,以便於互相識別。
flask-redis多機實戰
接下來我們將之前的那個flask-redis實戰轉換爲多機的實戰
首先準備兩臺服務器,我這裏準備了兩臺服務器分別是node1和node2,他們的ip地址分別是:192.168.205.10
和192.168.205.11
接下來在node1節點上運行命令
vagrant@node1:~$ wget https://github.com/coreos/etcd/releases/download/v3.0.12/etcd-v3.0.12-linux-amd64.tar.gz
vagrant@node1:~$ tar zxvf etcd-v3.0.12-linux-amd64.tar.gz
vagrant@node1:~$ cd etcd-v3.0.12-linux-amd64
vagrant@node1:~$ nohup ./etcd --name docker-node1 --initial-advertise-peer-urls http://192.168.205.10:2380 \
--listen-peer-urls http://192.168.205.10:2380 \
--listen-client-urls http://192.168.205.10:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://192.168.205.10:2379 \
--initial-cluster-token etcd-cluster \
--initial-cluster docker-node1=http://192.168.205.10:2380,docker-node2=http://192.168.205.11:2380 \
--initial-cluster-state new&
之後在node2上運行命令
vagrant@node2:~$ wget https://github.com/coreos/etcd/releases/download/v3.0.12/etcd-v3.0.12-linux-amd64.tar.gz
vagrant@node2:~$ tar zxvf etcd-v3.0.12-linux-amd64.tar.gz
vagrant@node2:~$ cd etcd-v3.0.12-linux-amd64/
vagrant@node2:~$ nohup ./etcd --name docker-node2 --initial-advertise-peer-urls http://192.168.205.11:2380 \
--listen-peer-urls http://192.168.205.11:2380 \
--listen-client-urls http://192.168.205.11:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://192.168.205.11:2379 \
--initial-cluster-token etcd-cluster \
--initial-cluster docker-node1=http://192.168.205.10:2380,docker-node2=http://192.168.205.11:23
檢查一下etcd的狀態:
vagrant@node2:~/etcd-v3.0.12-linux-amd64$ ./etcdctl cluster-health
接下來我們要重啓docker服務
在node1上運行命令
sudo service docker stop
sudo /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://192.168.205.10:2379 --cluster-advertise=192.168.205.10:2375&
在node2上運行命令
sudo service docker stop
sudo /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://192.168.205.11:2379 --cluster-advertise=192.168.205.11:2375&
接下來我們在node1上創建一個名爲demo的overlay網絡
docker network create -d overlay demo
我們現在在node1和node2上查看一下網絡情況
我們雖然沒有在node2上創建demo網絡,但是通過etcd會同步的進行創建,這樣我們兩臺服務器上都有了一個叫做demo的網絡,接下來我們創建容器時就可以將demo作爲容器的網絡。
首先在node2上創建redis容器
docker run -d --name redis --net demo redis
接下來在node1上創建flask容器
docker run -d --net demo -p 5000:5000 --name flask-redis -e REDIS_HOST=redis su/flask-redis
接下來我們看一下實驗結果
可以看到我們已經實現了多容器應用的多機部署💯。
歡迎大家關注我們的公衆號:知識沉澱部落。