《Docker環(huán)境下的前后端分離部署與運維》課程腳本
[TOC]
一、Docker虛擬機(jī)常用命令
-
先更新軟件包
yum -y update
-
安裝Docker虛擬機(jī)
yum install -y docker
-
運行、重啟、關(guān)閉Docker虛擬機(jī)
service docker start service docker start service docker stop
-
搜索鏡像
docker search 鏡像名稱
-
下載鏡像
docker pull 鏡像名稱
-
查看鏡像
docker images
-
刪除鏡像
docker rmi 鏡像名稱
-
運行容器
docker run 啟動參數(shù) 鏡像名稱
-
查看容器列表
docker ps -a
停止、掛起、恢復(fù)容器
docker stop 容器ID
docker pause 容器ID
docker unpase 容器ID
-
查看容器信息
docker inspect 容器ID
-
刪除容器
docker rm 容器ID
-
數(shù)據(jù)卷管理
docker volume create 數(shù)據(jù)卷名稱 #創(chuàng)建數(shù)據(jù)卷 docker volume rm 數(shù)據(jù)卷名稱 #刪除數(shù)據(jù)卷 docker volume inspect 數(shù)據(jù)卷名稱 #查看數(shù)據(jù)卷
-
網(wǎng)絡(luò)管理
docker network ls 查看網(wǎng)絡(luò)信息 docker network create --subnet=網(wǎng)段 網(wǎng)絡(luò)名稱 docker network rm 網(wǎng)絡(luò)名稱
-
避免VM虛擬機(jī)掛起恢復(fù)之后,Docker虛擬機(jī)斷網(wǎng)
vi /etc/sysctl.conf
文件中添加`net.ipv4.ip_forward=1`這個配置
?```shell
#重啟網(wǎng)絡(luò)服務(wù)
systemctl restart network
?```
二、安裝PXC集群,負(fù)載均衡,雙機(jī)熱備
-
安裝PXC鏡像
docker pull percona/percona-xtradb-cluster:5.7.21
強(qiáng)烈推薦同學(xué)們安裝5.7.21版本的PXC鏡像,兼容性最好,在容器內(nèi)可以執(zhí)行apt-get安裝各種程序包。最新版的PXC鏡像內(nèi),無法執(zhí)行apt-get,也就沒法安裝熱備份工具了。
-
為PXC鏡像改名
docker tag percona/percona-xtradb-cluster pxc
-
創(chuàng)建net1網(wǎng)段
docker network create --subnet=172.18.0.0/16 net1
-
創(chuàng)建5個數(shù)據(jù)卷
docker volume create --name v1 docker volume create --name v2 docker volume create --name v3 docker volume create --name v4 docker volume create --name v5
-
創(chuàng)建備份數(shù)據(jù)卷(用于熱備份數(shù)據(jù))
docker volume create --name backup
-
創(chuàng)建5節(jié)點的PXC集群
注意,每個MySQL容器創(chuàng)建之后,因為要執(zhí)行PXC的初始化和加入集群等工作,耐心等待1分鐘左右再用客戶端連接MySQL。另外,必須第1個MySQL節(jié)點啟動成功,用MySQL客戶端能連接上之后,再去創(chuàng)建其他MySQL節(jié)點。
#創(chuàng)建第1個MySQL節(jié)點 docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -v v1:/var/lib/mysql -v backup:/data --privileged --name=node1 --net=net1 --ip 172.18.0.2 pxc #創(chuàng)建第2個MySQL節(jié)點 docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=node1 -v v2:/var/lib/mysql -v backup:/data --privileged --name=node2 --net=net1 --ip 172.18.0.3 pxc #創(chuàng)建第3個MySQL節(jié)點 docker run -d -p 3308:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=node1 -v v3:/var/lib/mysql --privileged --name=node3 --net=net1 --ip 172.18.0.4 pxc #創(chuàng)建第4個MySQL節(jié)點 docker run -d -p 3309:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=node1 -v v4:/var/lib/mysql --privileged --name=node4 --net=net1 --ip 172.18.0.5 pxc #創(chuàng)建第5個MySQL節(jié)點 docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=node1 -v v5:/var/lib/mysql -v backup:/data --privileged --name=node5 --net=net1 --ip 172.18.0.6 pxc
-
安裝Haproxy鏡像
docker pull haproxy
-
宿主機(jī)上編寫Haproxy配置文件
vi /home/soft/haproxy/haproxy.cfg
配置文件如下:
global #工作目錄 chroot /usr/local/etc/haproxy #日志文件,使用rsyslog服務(wù)中l(wèi)ocal5日志設(shè)備(/var/log/local5),等級info log 127.0.0.1 local5 info #守護(hù)進(jìn)程運行 daemon defaults log global mode http #日志格式 option httplog #日志中不記錄負(fù)載均衡的心跳檢測記錄 option dontlognull #連接超時(毫秒) timeout connect 5000 #客戶端超時(毫秒) timeout client 50000 #服務(wù)器超時(毫秒) timeout server 50000 #監(jiān)控界面 listen admin_stats #監(jiān)控界面的訪問的IP和端口 bind 0.0.0.0:8888 #訪問協(xié)議 mode http #URI相對地址 stats uri /dbs #統(tǒng)計報告格式 stats realm Global\ statistics #登陸帳戶信息 stats auth admin:abc123456 #數(shù)據(jù)庫負(fù)載均衡 listen proxy-mysql #訪問的IP和端口 bind 0.0.0.0:3306 #網(wǎng)絡(luò)協(xié)議 mode tcp #負(fù)載均衡算法(輪詢算法) #輪詢算法:roundrobin #權(quán)重算法:static-rr #最少連接算法:leastconn #請求源IP算法:source balance roundrobin #日志格式 option tcplog #在MySQL中創(chuàng)建一個沒有權(quán)限的haproxy用戶,密碼為空。Haproxy使用這個賬戶對MySQL數(shù)據(jù)庫心跳檢測 option mysql-check user haproxy server MySQL_1 172.18.0.2:3306 check weight 1 maxconn 2000 server MySQL_2 172.18.0.3:3306 check weight 1 maxconn 2000 server MySQL_3 172.18.0.4:3306 check weight 1 maxconn 2000 server MySQL_4 172.18.0.5:3306 check weight 1 maxconn 2000 server MySQL_5 172.18.0.6:3306 check weight 1 maxconn 2000 #使用keepalive檢測死鏈 option tcpka
-
創(chuàng)建兩個Haproxy容器
#創(chuàng)建第1個Haproxy負(fù)載均衡服務(wù)器 docker run -it -d -p 4001:8888 -p 4002:3306 -v /home/soft/haproxy:/usr/local/etc/haproxy --name h1 --privileged --net=net1 --ip 172.18.0.7 haproxy #進(jìn)入h1容器,啟動Haproxy docker exec -it h1 bash haproxy -f /usr/local/etc/haproxy/haproxy.cfg #創(chuàng)建第2個Haproxy負(fù)載均衡服務(wù)器 docker run -it -d -p 4003:8888 -p 4004:3306 -v /home/soft/haproxy:/usr/local/etc/haproxy --name h2 --privileged --net=net1 --ip 172.18.0.8 haproxy #進(jìn)入h2容器,啟動Haproxy docker exec -it h2 bash haproxy -f /usr/local/etc/haproxy/haproxy.cfg
Haproxy容器內(nèi)安裝Keepalived,設(shè)置虛擬IP
注意事項:云主機(jī)不支持虛擬IP,另外很多公司的網(wǎng)絡(luò)禁止創(chuàng)建虛擬IP(回家創(chuàng)建),還有宿主機(jī)一定要關(guān)閉防火墻和SELINUX,很多同學(xué)都因為這個而失敗的,切記切記
#進(jìn)入h1容器
docker exec -it h1 bash
#更新軟件包
apt-get update
#安裝VIM
apt-get install vim
#安裝Keepalived
apt-get install keepalived
#編輯Keepalived配置文件(參考下方配置文件)
vim /etc/keepalived/keepalived.conf
#啟動Keepalived
service keepalived start
#宿主機(jī)執(zhí)行ping命令
ping 172.18.0.201
配置文件內(nèi)容如下:
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
172.18.0.201
}
}
#進(jìn)入h2容器
docker exec -it h2 bash
#更新軟件包
apt-get update
#安裝VIM
apt-get install vim
#安裝Keepalived
apt-get install keepalived
#編輯Keepalived配置文件
vim /etc/keepalived/keepalived.conf
#啟動Keepalived
service keepalived start
#宿主機(jī)執(zhí)行ping命令
ping 172.18.0.201
配置文件內(nèi)容如下:
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
172.18.0.201
}
}
-
宿主機(jī)安裝Keepalived,實現(xiàn)雙機(jī)熱備
#宿主機(jī)執(zhí)行安裝Keepalived yum -y install keepalived #修改Keepalived配置文件 vi /etc/keepalived/keepalived.conf #啟動Keepalived service keepalived start
Keepalived配置文件如下:
vrrp_instance VI_1 { state MASTER interface ens33 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.99.150 } } virtual_server 192.168.99.150 8888 { delay_loop 3 lb_algo rr lb_kind NAT persistence_timeout 50 protocol TCP real_server 172.18.0.201 8888 { weight 1 } } virtual_server 192.168.99.150 3306 { delay_loop 3 lb_algo rr lb_kind NAT persistence_timeout 50 protocol TCP real_server 172.18.0.201 3306 { weight 1 } }
-
熱備份數(shù)據(jù)
#進(jìn)入node1容器 docker exec -it node1 bash #更新軟件包 apt-get update #安裝熱備工具 apt-get install percona-xtrabackup-24 #全量熱備 innobackupex --user=root --password=abc123456 /data/backup/full
-
冷還原數(shù)據(jù)
停止其余4個節(jié)點,并刪除節(jié)點docker stop node2 docker stop node3 docker stop node4 docker stop node5 docker rm node2 docker rm node3 docker rm node4 docker rm node5
node1容器中刪除MySQL的數(shù)據(jù)
#刪除數(shù)據(jù) rm -rf /var/lib/mysql/* #清空事務(wù) innobackupex --user=root --password=abc123456 --apply-back /data/backup/full/2018-04-15_05-09-07/ #還原數(shù)據(jù) innobackupex --user=root --password=abc123456 --copy-back /data/backup/full/2018-04-15_05-09-07/
重新創(chuàng)建其余4個節(jié)點,組件PXC集群
三、PXC 特別注意事項
PXC的主節(jié)點和從節(jié)點分別代表什么意義?
PXC中的主節(jié)點和從節(jié)點跟Replication主從節(jié)點是有巨大差別的。
首先Replication集群的數(shù)據(jù)同步只能是從主節(jié)點到從節(jié)點,而且節(jié)點的身份是固定的,主節(jié)點永遠(yuǎn)是Master,從節(jié)點永遠(yuǎn)是Slave,不能互換。
但是PXC上的主節(jié)點指的是第一個啟動的節(jié)點,它不僅要啟動MySQL服務(wù),還要用Galera創(chuàng)建PXC集群。這些工作完成之后,主節(jié)點自動降級成普通節(jié)點。其他節(jié)點啟動的時候只需要啟動MySQL服務(wù),然后再加入到PXC集群即可,所以這些節(jié)點從啟動到關(guān)閉,身份一直都是普通節(jié)點。
為什么Node1能啟動,而其他的PXC節(jié)點啟動就閃退呢?
這是因為Node1啟動的時候要做跟多工作,上面已經(jīng)提及了。所以你沒等node1把PXC集群創(chuàng)建出來,你就飛快的啟動其他PXC節(jié)點,它們找不到Node1啟動的PXC集群,所以就自動閃退了。
正確的辦法是啟動Node1之后,等待10秒鐘,然后用Navicat訪問一下,能訪問了,再去啟動其他PXC節(jié)點
如果PXC集群在運行的狀態(tài)下,在宿主機(jī)上直接關(guān)機(jī),或者停止Docker服務(wù),為什么下次啟動哪個PXC節(jié)點都會閃退?
這個要從PXC集群的節(jié)點管理說起,PXC節(jié)點的數(shù)據(jù)目錄是/var/lib/mysql,好在這個目錄被我們映射到數(shù)據(jù)卷上了。比如你訪問v1數(shù)據(jù)卷就能看到node1的數(shù)據(jù)目錄。這其中有個grastate.dat的文件,它里面有個safe_to_bootstrap參數(shù)被PXC用來記載誰是最后退出PXC集群的節(jié)點。比如node1是最后關(guān)閉的節(jié)點,那么PXC就會在把safe_to_bootstrap設(shè)置成1,代表node1節(jié)點最后退出,它的數(shù)據(jù)是最新的。下次啟動必須先啟動node1,然后其他節(jié)點與node1同步。
如果你在PXC節(jié)點都正常運行的狀態(tài)下關(guān)閉宿主機(jī)Docker服務(wù)或者電源,那么PXC來不及判斷誰是最后退出的節(jié)點,所有PXC節(jié)點一瞬間就都關(guān)上了,哪個節(jié)點的safe_to_boostrap參數(shù)就都是0。解決這個故障也很好辦,那就是挑node1,把該參數(shù)改成1,然后正常啟動node1,再啟動其他節(jié)點就行了。
PXC集群只有一個節(jié)點,關(guān)閉了這個節(jié)點的容器,下次還能啟動起來嗎?
當(dāng)然是可以的,因為PXC里只有一個節(jié)點,那么這個節(jié)點一定是按照主節(jié)點啟動的,所以啟動它的時候,它會啟動MySQL服務(wù),還創(chuàng)建出PXC集群。即便關(guān)閉了容器,下次再啟動還是這個步驟,不會出現(xiàn)啟動故障。如果說PXC集群是由多個節(jié)點組成的,node1停掉了,其他節(jié)點都正常運行。這時候啟動node1是會出現(xiàn)閃退的,node1剛啟動幾秒鐘就掛了。這是因為node2等一些節(jié)點正在現(xiàn)有的PXC中運行,這時候你啟動node1,再創(chuàng)建一個同名的PXC集群,肯定會引發(fā)沖突啊。所以node1就閃退了。
遇到這種情況,正確的處理辦法是,把node1容器刪除。別緊張,沒讓你刪除v1數(shù)據(jù)卷,所以數(shù)據(jù)丟不了。然后用從節(jié)點的命令方式創(chuàng)建一個node1,啟動參數(shù)中與某個節(jié)點同步的設(shè)置就隨便選擇一個現(xiàn)在運行的PXC節(jié)點,然后Node1就能啟動了。
關(guān)于搭建技術(shù)體系,深入學(xué)習(xí)方面的感言
? 本門課程的數(shù)據(jù)庫部分只講到數(shù)據(jù)庫集群怎么搭建,如果想要完全駕馭數(shù)據(jù)庫,僅憑這點知識還是遠(yuǎn)遠(yuǎn)不夠的。像我在PXC免費課中講到的,我們首先要有一個明確的知識體系,下一步就是做知識分解,一點點把技術(shù)拼圖給完成。我見過非常多,東學(xué)一下,西學(xué)一下的人,即便有10年的工作經(jīng)驗,依然難成大器。比如說前些年VR挺火的,現(xiàn)在區(qū)塊鏈技術(shù)也挺火的。我是個快要畢業(yè)的大學(xué)生,我想學(xué)這些技術(shù)幫我找一份好的工作。其實這種想法不是不對,但是過于急功近利。我先把話題說的遠(yuǎn)一點,咱們一會兒再回來說技術(shù)規(guī)劃的事情。
? 在2013年,雷軍和董明珠打了個賭,如果小米在5年內(nèi)營業(yè)額超過格力,董明珠輸給雷軍10個億,反之也是如此。兩家企業(yè)相比較,大家更看好雷軍的小米。這是因為中國的制造業(yè)利潤太薄,制造業(yè)盈利存在上限的天花板,所以我們能準(zhǔn)確預(yù)測出一家制造業(yè)企業(yè)未來的盈利空間。但是互聯(lián)網(wǎng)公司就不是這樣,想象空間太巨大。比如說馬云的阿里巴巴,從1999年創(chuàng)建,到2014年上市,用了15年時間。劉強(qiáng)東的京東商城,差不多也用了15年時間上市。但是到了黃錚的拼多多這里,只用了3年時間就完成了上市,他還一舉超過劉強(qiáng)東,成為中國第六富豪。IT界一夜成名的還有滴滴打車的程維、美團(tuán)的王興等等。
? 也正是IT互聯(lián)網(wǎng)公司造富神話太多,也就越來越多的資本涌入IT圈。有的資本公司做長線,但是更多的資本公司炒短線。先投資一家小公司,然后再制造行業(yè)輿論和技術(shù)導(dǎo)向,當(dāng)人們被技術(shù)忽悠的瘋狂的時候,有人肯接盤了,這時候再把投資的這家小公司賣掉,割一波韭菜就撤。于是我們看到太多太多被熱炒的技術(shù),沒過1年時間就無人問津了。比如2014年的iOS技術(shù),2015年的VR技術(shù)等等。當(dāng)年VR技術(shù)被捧到天上,王雪紅一度被業(yè)界認(rèn)為會用VR讓HTC翻身,可是到現(xiàn)在我們再也聽不到HTC這家公司的新聞了。活著還是倒閉了,我們都不知道,大家也不關(guān)心。
? 所以我們選擇一個技術(shù)方向的時候,首先要看這個領(lǐng)域是不是有太多的水分,是不是有太多的熱錢。比如今年3月的時候,真格基金的徐小平發(fā)了一個微博說自己非常看好以太坊技術(shù),于是短短時間,中國各家資本公司紛紛涌入?yún)^(qū)塊鏈領(lǐng)域。甚至還出現(xiàn)了2萬塊錢的區(qū)塊鏈講師速成班,不管懂不懂計算機(jī),都能給你在短期內(nèi)培養(yǎng)成區(qū)塊鏈專家,然后你再去培訓(xùn)機(jī)構(gòu)忽悠人,月薪兩萬,割學(xué)技術(shù)大學(xué)生的韭菜。我想,徐小平在微博上把區(qū)塊鏈捧到天上,何嘗不是一種資本炒作的手法呢。
? 最后說回到技術(shù)領(lǐng)域這塊。比如你是一個大學(xué)生,想投身一個有發(fā)展的技術(shù)方向,那么不妨拿起手機(jī)看看那些常用的APP上都用到了什么技術(shù),這才是能落地能普及的。比如說刷抖音很容易上癮,上劃一條是你喜歡的視頻,再上劃一下,又是你感興趣的視頻。還有每個人打開淘寶APP,首頁的內(nèi)容都不一樣,都是你喜歡的商品,看什么東西都想賣。淘寶也很絕,即使你不花錢買東西,只要你點擊看了一個你喜歡的商品,從此以后,你各項愛好都被淘寶所感知了。這種技術(shù)是大數(shù)據(jù)上的協(xié)同過濾。說簡單一點,就是掌握了你很少資料的情況下,去分析跟你有相同行為的人的喜好,于是推算出你的喜好。比如你點擊了某個牌子的運動鞋,那么淘寶的協(xié)同過濾就會計算購買了這個運動鞋的用戶,還買了什么東西,這些用戶共性的東西,就是你的愛好。所以你再打開淘寶APP,看到的都是你喜歡的東西。抖音啊,今日頭條啊,都是這樣的技術(shù)。所以你學(xué)大數(shù)據(jù),這個技術(shù)是能落地的,太多產(chǎn)品在用這個技術(shù)了。相比較而言,區(qū)塊鏈和人工智能就顯得太高冷了。不是說技術(shù)不好,但是距離大規(guī)模普及還是有很遠(yuǎn)的距離。比如說區(qū)塊鏈吧,上半年好多企業(yè)都在炒作,不跟區(qū)塊鏈掛鉤好像都不是科技企業(yè),甚至南方有家茶葉公司,把名字都改成了帶有區(qū)塊鏈字眼。這就像荷蘭的郁金香泡沫,當(dāng)人們都意識到郁金香根本就不值那么高價格的時候,于是泡沫就破裂了。比如極路由公司,把自己的路由器搞成了能挖礦,每天平均賺4塊錢。我們知道1萬塊錢存到支付寶上,一天也產(chǎn)生不了1塊錢的利益。現(xiàn)在幾百塊錢的極路由每天產(chǎn)生4塊錢的收益,不就相當(dāng)你花幾百塊錢享受幾萬塊錢的利息收益嗎,多讓人瘋狂啊。極路由一邊忽悠消費者,一邊又去忽悠投資人,還跟互聯(lián)網(wǎng)金融公司合作,弄了多種套餐玩法。投資人和消費者都被忽悠熱血沸騰,拿出十幾萬塊錢,買極路由器,幻想自己在家當(dāng)?shù)刂鳎焯鞄装賶K錢收入。但是不到半年時間,極路由的技術(shù)+金融戲法就玩不下去了,老板欠了3.5個億跑路了。同學(xué)們也不妨搜索一下因為區(qū)塊鏈破產(chǎn)的消費者和炒作者。你投身這樣的領(lǐng)域覺得靠譜嗎?
? 所以選擇技術(shù)規(guī)劃一定要挑選成熟的,應(yīng)用范圍廣泛的。比如大數(shù)據(jù)、Java體系、前端體系、Python體系等等。所以就像我在免費課里說到的,你選擇好一個發(fā)力的方向,剩下的就是如何分解知識點了。比如說,你學(xué)了Java的一部分,沒去深挖微服務(wù)架構(gòu)和集群架構(gòu)。如果你只停留在做單體項目,比如說SSM實現(xiàn)一個管理項目,VUE做一個網(wǎng)站等等,那我可以保證,你在IT開發(fā)這個領(lǐng)域很難堅持10年。經(jīng)常聽說,做開發(fā)30歲要轉(zhuǎn)行,公司里幾乎看不見40歲還做開發(fā)的人。其中的原因很多人沒講到關(guān)鍵點,作為創(chuàng)業(yè)者和企業(yè)家的角度來看,如果一個開發(fā)者,技術(shù)只停留在用SSM架構(gòu)套各種業(yè)務(wù),今天做一個管理系統(tǒng),明天做一個管理系統(tǒng)。因為單體項目很難支撐高并發(fā),所以你做的項目基本都是在小公司內(nèi)部使用。隨著你工作年限增加,對企業(yè)來說用人成本也就變高了。用一個2年經(jīng)驗的開發(fā)者,也會使用SSM做項目,成本還低,那為什么不用這樣的人呢。所以你就被企業(yè)無情的拋棄了,根本原因是技術(shù)停滯,成本太高。這時候你再想跳槽到大企業(yè),技術(shù)和年齡都達(dá)不到要求了。所以我建議年輕人,參加工作以后,雖然崗位有界限,但是技術(shù)無界限。前端、后臺、數(shù)據(jù)庫、原型設(shè)計、項目管理,多少都要學(xué)一些,沒人教,就自己總結(jié)。只有技術(shù)全才,才能勝任技術(shù)團(tuán)隊的管理者,才不會被企業(yè)淘汰。
? 其實我見過很多項目都是被不稱職的管理者給弄黃的。也許你也有同感,這個項目A公司做過,B公司做過,現(xiàn)在客戶找到我們又要重做一版,這是為什么呢?項目開發(fā)的失敗率也太高了吧。這通常是項目管理者技術(shù)不過關(guān)導(dǎo)致的,比如說A客戶去南方考察,覺得某公司的管理系統(tǒng)特別好,我想也做一套。于是找到了你,A客戶是大老板,下面具體的業(yè)務(wù)細(xì)節(jié)說不太清楚,腦子里也沒有清晰的想法,反正想到什么就東一句、西一句的,然后你貿(mào)然選用了瀑布模型開發(fā)。經(jīng)過了需求分析、文檔設(shè)計,總算進(jìn)入到了開發(fā)。經(jīng)過兩個月的開發(fā),終于可以拿出半成品給A客戶了,這時候A客戶說你做的不是他想要的東西,要不你推到重做把,要不我找別的公司去做。然后別的公司做了,A客戶依然不滿意,于是開啟了無限的重做模式。
? 究其原因還是管理者用錯了開發(fā)模型,瀑布模型看似合理,但是問題在于編碼階段太靠后,等拿出半成品已經(jīng)小半年時間過去了。因此瀑布模型適用于那種能提出明確需求,而且到每一處細(xì)節(jié)的客戶。像A客戶這樣的人,我們應(yīng)該用螺旋模型去開發(fā),小規(guī)模快速迭代,只開發(fā)最核心模塊,短期內(nèi)就拿出演示品跟客戶確認(rèn)。這種小步快跑的策略適合提不出具體需求和需求不明確的場合。所以說,同學(xué),以后你想做管理者,是不是得了解“軟件工程”的知識啊!
? 這幾年我在教育部舉辦的互聯(lián)網(wǎng)+創(chuàng)新創(chuàng)業(yè)大賽預(yù)賽和決賽當(dāng)評委的時候,跟很多大學(xué)生創(chuàng)業(yè)的同學(xué)講到了,你的創(chuàng)業(yè)想法很好,但是很可能項目會作廢了。起初他們不相信,覺得自己拿到風(fēng)投的錢,幾個學(xué)軟件的同學(xué)會編程,這就足夠了。于是次年的時候,我又見到了這些同學(xué),參賽的題目又換了。我就好奇的問他們,去年的創(chuàng)業(yè)項目做成了嗎?他們跟我說,創(chuàng)業(yè)項目做砸了。呵呵,果然是這樣。因為他們的團(tuán)隊里缺少了技術(shù)方面的全才。僅靠專才是不能完成項目開發(fā)的。我再舉一個例子,某公司的開發(fā)者老張,他是做后端比較擅長,因為工作年頭比較長了,于是就被提拔成了項目經(jīng)理。有一天,日方客戶發(fā)來一封郵件,說某模塊的業(yè)務(wù)流程要修改,看看中方這邊多長時間能實現(xiàn),費用是多少。于是老張就召集團(tuán)隊的人開了一次會。老張擅長后臺開發(fā),這次需求覺得沒什么難度,然后問了問數(shù)據(jù)庫的哥們和前端的哥們,他們說也好實現(xiàn),然后老張就承諾日方兩天就能做完。但是過于樂觀的態(tài)度,很容易引來噩夢般的后果。數(shù)據(jù)庫的哥們和前端的哥們,寫代碼的時候才發(fā)現(xiàn)實現(xiàn)難度很大,最后花了半個月才做完,浪費了大量的加班費用。因為老張不懂前端,也不懂?dāng)?shù)據(jù)庫集群,覺得底下人說什么就代表什么。由此看出,管理者技術(shù)必須全面,不能人云亦云,必須保持自己的判斷力。
? 說了這么多,也非常感謝大家在慕課網(wǎng)上支持我的課程,后續(xù)我還會在慕課網(wǎng)上錄制更多的實戰(zhàn)課,將我們的技術(shù)體系拼圖給逐步完成。目前正在錄制Python的課程和其他的開發(fā)課程,請大家稍加等待。下面列出來我在慕課網(wǎng)上所有課程的連接,以供大家學(xué)習(xí)。
《MySQL數(shù)據(jù)庫集群-PXC方案》
https://coding.imooc.com/class/274.html
《Docker環(huán)境下的前后端分離項目部署與運維》
https://coding.imooc.com/class/219.html
安裝Redis,配置RedisCluster集群
-
安裝Redis鏡像
docker pull yyyyttttwwww/redis
-
創(chuàng)建net2網(wǎng)段
docker network create --subnet=172.19.0.0/16 net2
-
創(chuàng)建6節(jié)點Redis容器
docker run -it -d --name r1 -p 5001:6379 --net=net2 --ip 172.19.0.2 redis bash docker run -it -d --name r2 -p 5002:6379 --net=net2 --ip 172.19.0.3 redis bash docker run -it -d --name r3 -p 5003:6379 --net=net2 --ip 172.19.0.4 redis bash docker run -it -d --name r4 -p 5004:6379 --net=net2 --ip 172.19.0.5 redis bash docker run -it -d --name r5 -p 5005:6379 --net=net2 --ip 172.19.0.6 redis bash
注意:redis配置文件里必須要設(shè)置bind 0.0.0.0,這是允許其他IP可以訪問當(dāng)前redis。如果不設(shè)置這個參數(shù),就不能組建Redis集群。
-
啟動6節(jié)點Redis服務(wù)器
#進(jìn)入r1節(jié)點 docker exec -it r1 bash cp /home/redis/redis.conf /usr/redis/redis.conf cd /usr/redis/src ./redis-server ../redis.conf #進(jìn)入r2節(jié)點 docker exec -it r2 bash cp /home/redis/redis.conf /usr/redis/redis.conf cd /usr/redis/src ./redis-server ../redis.conf #進(jìn)入r3節(jié)點 docker exec -it r3 bash cp /home/redis/redis.conf /usr/redis/redis.conf cd /usr/redis/src ./redis-server ../redis.conf #進(jìn)入r4節(jié)點 docker exec -it r4 bash cp /home/redis/redis.conf /usr/redis/redis.conf cd /usr/redis/src ./redis-server ../redis.conf #進(jìn)入r5節(jié)點 docker exec -it r5 bash cp /home/redis/redis.conf /usr/redis/redis.conf cd /usr/redis/src ./redis-server ../redis.conf #進(jìn)入r6節(jié)點 docker exec -it r6 bash cp /home/redis/redis.conf /usr/redis/redis.conf cd /usr/redis/src ./redis-server ../redis.conf
-
創(chuàng)建Cluster集群
#在r1節(jié)點上執(zhí)行下面的指令 cd /usr/redis/src mkdir -p ../cluster cp redis-trib.rb ../cluster/ cd ../cluster #創(chuàng)建Cluster集群 ./redis-trib.rb create --replicas 1 172.19.0.2:6379 172.19.0.3:6379 172.19.0.4:6379 172.19.0.5:6379 172.19.0.6:6379 172.19.0.7:6379
打包部署后端項目
-
進(jìn)入人人開源后端項目,執(zhí)行打包(修改配置文件,更改端口,打包三次生成三個JAR文件)
mvn clean install -Dmaven.test.skip=true
-
安裝Java鏡像
docker pull java
-
創(chuàng)建3節(jié)點Java容器
#創(chuàng)建數(shù)據(jù)卷,上傳JAR文件 docker volume create j1 #啟動容器 docker run -it -d --name j1 -v j1:/home/soft --net=host java #進(jìn)入j1容器 docker exec -it j1 bash #啟動Java項目 nohup java -jar /home/soft/renren-fast.jar #創(chuàng)建數(shù)據(jù)卷,上傳JAR文件 docker volume create j2 #啟動容器 docker run -it -d --name j2 -v j2:/home/soft --net=host java #進(jìn)入j1容器 docker exec -it j2 bash #啟動Java項目 nohup java -jar /home/soft/renren-fast.jar #創(chuàng)建數(shù)據(jù)卷,上傳JAR文件 docker volume create j3 #啟動容器 docker run -it -d --name j3 -v j3:/home/soft --net=host java #進(jìn)入j1容器 docker exec -it j3 bash #啟動Java項目 nohup java -jar /home/soft/renren-fast.jar
-
安裝Nginx鏡像
docker pull nginx
-
創(chuàng)建Nginx容器,配置負(fù)載均衡
宿主機(jī)上/home/n1/nginx.conf配置文件內(nèi)容如下:
user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 5s; proxy_send_timeout 5s; proxy_read_timeout 5s; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; upstream tomcat { server 192.168.99.104:6001; server 192.168.99.104:6002; server 192.168.99.104:6003; } server { listen 6101; server_name 192.168.99.104; location / { proxy_pass http://tomcat; index index.html index.htm; } } }
創(chuàng)建第1個Nginx節(jié)點
docker run -it -d --name n1 -v /home/n1/nginx.conf:/etc/nginx/nginx.conf --net=host --privileged nginx
宿主機(jī)上/home/n2/nginx.conf配置文件內(nèi)容如下:
user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 5s; proxy_send_timeout 5s; proxy_read_timeout 5s; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; upstream tomcat { server 192.168.99.104:6001; server 192.168.99.104:6002; server 192.168.99.104:6003; } server { listen 6102; server_name 192.168.99.104; location / { proxy_pass http://tomcat; index index.html index.htm; } } }
創(chuàng)建第2個Nginx節(jié)點
docker run -it -d --name n2 -v /home/n2/nginx.conf:/etc/nginx/nginx.conf --net=host --privileged nginx
-
在Nginx容器安裝Keepalived
#進(jìn)入n1節(jié)點 docker exec -it n1 bash #更新軟件包 apt-get update #安裝VIM apt-get install vim #安裝Keepalived apt-get install keepalived #編輯Keepalived配置文件(如下) vim /etc/keepalived/keepalived.conf #啟動Keepalived service keepalived start
vrrp_instance VI_1 { state MASTER interface ens33 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 192.168.99.151 } } virtual_server 192.168.99.151 6201 { delay_loop 3 lb_algo rr lb_kind NAT persistence_timeout 50 protocol TCP real_server 192.168.99.104 6101 { weight 1 } }
#進(jìn)入n1節(jié)點 docker exec -it n2 bash #更新軟件包 apt-get update #安裝VIM apt-get install vim #安裝Keepalived apt-get install keepalived #編輯Keepalived配置文件(如下) vim /etc/keepalived/keepalived.conf #啟動Keepalived service keepalived start
vrrp_instance VI_1 { state MASTER interface ens33 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 192.168.99.151 } } virtual_server 192.168.99.151 6201 { delay_loop 3 lb_algo rr lb_kind NAT persistence_timeout 50 protocol TCP real_server 192.168.99.104 6102 { weight 1 } }
打包部署后端項目
-
在前端項目路徑下執(zhí)行打包指令
npm run build
build目錄的文件拷貝到宿主機(jī)的/home/fn1/renren-vue、/home/fn2/renren-vue、/home/fn3/renren-vue的目錄下面
-
創(chuàng)建3節(jié)點的Nginx,部署前端項目
宿主機(jī)/home/fn1/nginx.conf的配置文件
user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 5s; proxy_send_timeout 5s; proxy_read_timeout 5s; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; server { listen 6501; server_name 192.168.99.104; location / { root /home/fn1/renren-vue; index index.html; } } }
#啟動第fn1節(jié)點 docker run -it -d --name fn1 -v /home/fn1/nginx.conf:/etc/nginx/nginx.conf -v /home/fn1/renren-vue:/home/fn1/renren-vue --privileged --net=host nginx
宿主機(jī)/home/fn2/nginx.conf的配置文件
user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 5s; proxy_send_timeout 5s; proxy_read_timeout 5s; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; server { listen 6502; server_name 192.168.99.104; location / { root /home/fn2/renren-vue; index index.html; } } }
#啟動第fn2節(jié)點 docker run -it -d --name fn2 -v /home/fn2/nginx.conf:/etc/nginx/nginx.conf -v /home/fn2/renren-vue:/home/fn2/renren-vue --privileged --net=host nginx
宿主機(jī)/home/fn3/nginx.conf的配置文件
user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 5s; proxy_send_timeout 5s; proxy_read_timeout 5s; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; server { listen 6503; server_name 192.168.99.104; location / { root /home/fn3/renren-vue; index index.html; } } }
啟動fn3節(jié)點
#啟動第fn3節(jié)點 docker run -it -d --name fn3 -v /home/fn3/nginx.conf:/etc/nginx/nginx.conf -v /home/fn3/renren-vue:/home/fn3/renren-vue --privileged --net=host nginx
-
配置負(fù)載均衡
宿主機(jī)/home/ff1/nginx.conf配置文件
user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 5s; proxy_send_timeout 5s; proxy_read_timeout 5s; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; upstream fn { server 192.168.99.104:6501; server 192.168.99.104:6502; server 192.168.99.104:6503; } server { listen 6601; server_name 192.168.99.104; location / { proxy_pass http://fn; index index.html index.htm; } } }
#啟動ff1節(jié)點 docker run -it -d --name ff1 -v /home/ff1/nginx.conf:/etc/nginx/nginx.conf --net=host --privileged nginx
宿主機(jī)/home/ff2/nginx.conf配置文件
user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 5s; proxy_send_timeout 5s; proxy_read_timeout 5s; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; upstream fn { server 192.168.99.104:6501; server 192.168.99.104:6502; server 192.168.99.104:6503; } server { listen 6602; server_name 192.168.99.104; location / { proxy_pass http://fn; index index.html index.htm; } } }
#啟動ff2節(jié)點 docker run -it -d --name ff2 -v /home/ff2/nginx.conf:/etc/nginx/nginx.conf --net=host --privileged nginx
-
配置雙機(jī)熱備
#進(jìn)入ff1節(jié)點 docker exec -it ff1 bash #更新軟件包 apt-get update #安裝VIM apt-get install vim #安裝Keepalived apt-get install keepalived #編輯Keepalived配置文件(如下) vim /etc/keepalived/keepalived.conf #啟動Keepalived service keepalived start
vrrp_instance VI_1 { state MASTER interface ens33 virtual_router_id 52 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 192.168.99.152 } } virtual_server 192.168.99.151 6701 { delay_loop 3 lb_algo rr lb_kind NAT persistence_timeout 50 protocol TCP real_server 192.168.99.104 6601 { weight 1 } }
#進(jìn)入ff1節(jié)點 docker exec -it ff2 bash #更新軟件包 apt-get update #安裝VIM apt-get install vim #安裝Keepalived apt-get install keepalived #編輯Keepalived配置文件(如下) vim /etc/keepalived/keepalived.conf #啟動Keepalived service keepalived start
vrrp_instance VI_1 { state MASTER interface ens33 virtual_router_id 52 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 192.168.99.152 } } virtual_server 192.168.99.151 6701 { delay_loop 3 lb_algo rr lb_kind NAT persistence_timeout 50 protocol TCP real_server 192.168.99.104 6602 { weight 1 } }
?