微服務Tars入門以及踩坑記錄
什么是微服務
近幾年,微服務這個詞闖入我們的視線范圍。通常跟微服務相對的是單體應用,即將所有功能都打包成在一個獨立單元的應用程序。微服務的架構就是將單個應用程序划分成各種小的、互相連接的微服務,一個微服務完成一個比較單一的功能,相互之間保持獨立和解耦合。不同服務內部的開發技術可以不一致。
當然,拆分成多個服務,關於服務的管理也引出了一系列問題。為了解決這些問題,提出了一系列概念:服務注冊與發現、服務監控、服務治理等等。微服務的這些問題可以通過引入微服務框架來幫助我們去解決。
目前業界比較成熟的微服務框架有阿里的Dubbo、Pivotal公司的Spring Cloud、騰訊的Tars、google的gRPC等等。
我這里選擇Tars作為入門學習的微服務框架。學習過程中,發現這跟我平時使用的PHP框架很不一樣,除了要學習使用TarsPHP這一開發框架,微服務的環境部署和發布節點之外,還涉及到很多網絡、服務器方面的知識。都是自己所欠缺需要惡補的。而且還需要考慮服務邊界的划分,服務與服務之間是如何調用的。
發布節點時報錯
使用docker-compose進行部署,發布節點的時候遇到問題: 出現batchPatch err:NodeImp.cpp:patchPro:111| error:ip 172.25.0.1 is invalid錯誤
看似一個ip無效的報錯,其實涉及到容器通信方面,必須先了解很多關於網絡的知識,才能逐一排查錯誤原因。這里就所涉及到的知識進行一個梳理,然后再排查分析。
docker 網絡
1. docker network操作
先查看下docker針對網絡有哪些操作,使用命令:docker network --help
比如create命令:
# 創建一個名為tars的橋接(bridge)虛擬網絡,網關172.25.0.1,網段為172.25.0.0
使用命令:docker network create -d bridge --subnet=172.25.0.0/16 --gateway=172.25.0.1 tars
我們也可以使用命令查看創建網絡的可選配置項:docker network create --help
如下圖:
2. docker的網絡模式
安裝 Docker 以后,會默認創建三種網絡,可以通過 docker network ls 查看:
1)bridge(橋接模式)
橋接模式是docker 的默認網絡設置,當docker服務啟動時,會在主機上創建一個名為docker0的虛擬以太網橋,並選擇一個和宿主機不同的IP地址和子網分配給docker0網橋。
示意圖:
網絡模式選擇橋接模式的容器,就會連接上docker0這個網橋,再通過nat的轉換,通過宿主機的網卡,連接外網,就能達到上外網的目的。
默認情況下,守護進程會創建一對對等虛擬設備接口 veth pair,將其中一個接口設置為容器的 eth0 接口(容器的網卡),另一個接口放置在宿主機的命名空間中,以類似 vethxxx 這樣的名字命名,從而將宿主機上的所有容器都連接到這個內部網絡上。
這里,我啟動了三個容器mysql、tars-node ,tars-framework,就會有三個容器網卡,以及一個docker0虛擬網卡,這三個容器網卡都會橋接到docker0網卡,docker0網卡與物理機網卡連接使用的是nat技術,如下圖:
使用命令:ip addr (ip a 或 ip add list),查看網卡狀態
使用命令查看bridge模式的詳細信息:docker network inspect bridge
2)host模式
該模式下容器是不會擁有自己的ip地址,而是使用宿主機的ip地址和端口。這種模式的好處就是網絡性能比橋接模式的好。缺點就是會占用宿主機的端口,網絡的隔離性不太好
3)none
none模式沒有IP地址,無法連接外網,等於就是斷網的狀態,作用就是用於測試,生產環境一般不會用到這種
4)container
新創建的容器不會創建自己的網卡和配置自己的 IP,而是和一個指定的容器共享 IP、端口范圍等。
3. docker-compose.yml文件分析
1 version: "3" 2 3 services: 4 mysql: 5 image: mysql:5.6 6 container_name: compose-tars-mysql 7 ports: 8 - "3307:3306" 9 restart: always 10 environment: 11 MYSQL_ROOT_PASSWORD: "123456" 12 volumes: 13 - ./mysql/data:/var/lib/mysql:rw 14 - ./source/Shanghai:/etc/localtime 15 networks: 16 internal: 17 ipv4_address: 172.25.1.2 18 framework: 19 image: tarscloud/framework:v2.4.0 20 container_name: compose-tars-framework 21 ports: 22 - "3000:3000" 23 - "3001:3001" 24 restart: always 25 networks: 26 internal: 27 ipv4_address: 172.25.1.3 28 environment: 29 MYSQL_HOST: "172.25.1.2" 30 # MYSQL_HOST: "123.56.***.184" 31 MYSQL_ROOT_PASSWORD: "123456" 32 MYSQL_USER: "root" 33 MYSQL_PORT: 3306 34 # MYSQL_PORT: 3307 35 REBUILD: "false" 36 INET: eth0 37 SLAVE: "false" 38 volumes: 39 - ./framework/data:/data/tars:rw 40 - ./source/Shanghai:/etc/localtime 41 depends_on: 42 - mysql 43 node: 44 image: tarscloud/tars-node:latest 45 container_name: compose-tars-node 46 restart: always 47 networks: 48 internal: 49 ipv4_address: 172.25.1.5 50 volumes: 51 - ./node/data:/data/tars:rw 52 - ./source/Shanghai:/etc/localtime 53 environment: 54 INET: eth0 55 WEB_HOST: http://172.25.1.3:3000 56 # WEB_HOST: http://123.56.***.184:3000 57 ports: 58 - "9000-9009:9000-9009" 59 depends_on: 60 - framework 61 networks: 62 internal: 63 driver: bridge 64 ipam: 65 config: 66 - subnet: 172.25.1.0/16
depends_on:定義容器啟動順序 (此選項解決了容器之間的依賴關系)
4. IP、網段、子網掩碼(網絡掩碼)
從上面看到networks的設置中,網段為172.25.1.0/16,這里面就涉及到ip、相同網段、網絡掩碼的相關知識。
1)什么是IP地址
IP地址相當於網絡中的身份唯一認證ID,跟身份證ID一樣是唯一的,唯一不同的是,IP地址是可以變的,只是不管怎么變,都將會是唯一的。Mac地址的性質更加接近於身份證ID,它是設備的唯一ID。
IP地址目前普遍是IPv4版本,由32位二進制數分成4組,每組1字節Byte(8Bit)組成。分別用十進制表示再用圓點隔開,就是現在的172.25.1.0。
2)IP地址的構成
IP地址 = 網絡地址 + 主機地址
比如:192.168.1.168(IP地址) = 192.168.1.0 (網絡地址) + 0.0.0.168(主機地址)
網絡地址、主機地址是怎么計算出來的呢?就需要先簡單學習下子網掩碼
3)子網掩碼(subnet mask)
比如這里的172.25.1.0/16中的16,指的是子網掩碼的長度,16代表16個1,用子網掩碼來表示,就是:255.255.0.0。它的作用主要是用來區分網絡地址和主機地址。
將ip地址轉為二進制,子網掩碼轉為二進制,通過按位與最終得到網段號。根據按位與的特性,可以看到172.25這個網段是不變的,后面的都可以改變。
排查錯誤原因
下面我們就開始提到用TarsDocker部署后,針對發布節點時遇到的錯誤進行排查分析。
分析:這個錯誤是這台機器上的tarnode識別過來的發布請求的非法,不是tarsAdminRegistry的ip。
1)查看想要發布節點到的對應容器
可以看到,這里發布的結點是172.25.1.5,我們是想通過這個ip發布到對應的容器tars-node
現在我們來看下這個容器的詳細信息:docker inspect containerid
根據報錯的信息:error:ip 172.25.0.1 is invalid,反應出tars找到的容器節點錯誤,找到的其實是網關,tars無法根據ip:172.25.0.1找到與它連接對應的容器,因此也就無法將服務發布到對相應容器。因此很快報ip無效的錯誤,流程根本都還沒有走到檢查打包的代碼這一步。
2) 考慮換成容器逐個啟動的方式,看能否成功發布節點
我先使用docker-compose down將啟動的容器都卸載,然后用docker run將mysql、tars-node、tars-framework逐個啟動
1 docker run --name tars-mysql -e MYSQL_ROOT_PASSWORD='123456' -d -p 3307:3306 \ 2 -v/etc/localtime:/etc/localtime \ 3 -v /data/mysql-data:/var/lib/mysql mysql:5.6 4 5 docker run -d \ 6 --name=tars-framework \ 7 -e MYSQL_HOST="123.56.***.184" \ 8 -e MYSQL_ROOT_PASSWORD="123456" \ 9 -e MYSQL_USER=root \ 10 -e MYSQL_PORT=3307 \ 11 -e REBUILD=false \ 12 -e SLAVE=false \ 13 -e INET=eth0 \ 14 -p 3000:3000 \ 15 -p 3001:3001 \ 16 -v /etc/localtime:/etc/localtime \ 17 -v /tmp/test/data:/data/tars \ 18 tarscloud/framework:v2.4.0 19 20 docker run -d \ 21 --name=tars-node \ 22 -e INET=eth0 \ 23 -e WEB_HOST="http://123.56.***.184:3000" \ 24 -p "9000-9010:9000-9010" \ 25 -v /data/tars:/data/tars \ 26 -v /etc/localtime:/etc/localtime \ 27 tarscloud/tars-node:latest 28
這里將服務部署和發布節點的流程走一遍,可以發布成功。於是進行分析:
容器通信的兩種方式:
1)不需要給容器建立虛擬網絡,直接通過eth0,也就是宿主機的外網環境直接訪問
2)容器的虛擬網絡,通過暴露端口給宿主機映射的端口,通過宿主機+映射的端口訪問。
這個地方用單個容器逐一啟動,發布節點時能把服務成功發布到相應容器,容器之間的通信是通過宿主機的外網環境直接訪問。
經過反復排查,最終定位到問題到docker的網絡設置不對,導致發布時tarnode獲得的ip地址是網關地址172.25.0.1,而不是容器的網絡地址,因而無法發布服務到相應的容器。
我這邊使用的是阿里雲服務器,通過重啟雲服務器,以及重新啟動docker。恢復正常。
TarsDocker重新部署
1. 重新部署,然后發布節點
docker-compose up 不加-d,我們來看下容器啟動的流程
可以看到,一個容器要等待它所依賴的其他容器啟動成功后,才能夠啟動。這期間開啟着定時任務,一直在嘗試着啟動各個容器,串行執行。
啟動之后,通過宿主機地址+端口訪問,注意右上角是tars-framework版本
2. 運維管理-服務部署
3. 發布節點
4. 切換到服務管理,刷新下頁面
5. 輸入地址,訪問下運行的服務
Ok,發布成功了,服務正常運行,並且能夠成功訪問了。
部署和發布的過程中可能會遇到各種各樣的問題,有問題是好事,重點是我們要有足夠的知識儲備,去一步一步排查,分析原因,解決問題。
參考鏈接:
https://juejin.cn/post/6868086876751085581#heading-1
https://blog.csdn.net/qq_33355821/article/details/104173831
https://segmentfault.com/a/1190000022864573
https://doc.tarsyun.com/adminer/start/index.html#/tarsdoc/gateway/README.md