《Docker環(huán)境下的前后端分離部署與運維》課程腳本
[TOC]
一匠襟、Docker虛擬機常用命令
-
先更新軟件包
yum -y update
-
安裝Docker虛擬機
yum install -y docker
-
運行、重啟管搪、關(guān)閉Docker虛擬機
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虛擬機掛起恢復(fù)之后烫沙,Docker虛擬機斷網(wǎng)
vi /etc/sysctl.conf
文件中添加`net.ipv4.ip_forward=1`這個配置
?```shell
#重啟網(wǎng)絡(luò)服務(wù)
systemctl restart network
?```
二、安裝PXC集群隙笆,負載均衡锌蓄,雙機熱備
-
安裝PXC鏡像
docker pull percona/percona-xtradb-cluster:5.7.21
強烈推薦同學(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
-
宿主機上編寫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 #守護進程運行 daemon defaults log global mode http #日志格式 option httplog #日志中不記錄負載均衡的心跳檢測記錄 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ù)庫負載均衡 listen proxy-mysql #訪問的IP和端口 bind 0.0.0.0:3306 #網(wǎng)絡(luò)協(xié)議 mode tcp #負載均衡算法(輪詢算法) #輪詢算法: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負載均衡服務(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 #進入h1容器,啟動Haproxy docker exec -it h1 bash haproxy -f /usr/local/etc/haproxy/haproxy.cfg #創(chuàng)建第2個Haproxy負載均衡服務(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 #進入h2容器累舷,啟動Haproxy docker exec -it h2 bash haproxy -f /usr/local/etc/haproxy/haproxy.cfg
Haproxy容器內(nèi)安裝Keepalived浩考,設(shè)置虛擬IP
注意事項:云主機不支持虛擬IP,另外很多公司的網(wǎng)絡(luò)禁止創(chuàng)建虛擬IP(回家創(chuàng)建),還有宿主機一定要關(guān)閉防火墻和SELINUX被盈,很多同學(xué)都因為這個而失敗的析孽,切記切記
#進入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
#宿主機執(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
}
}
#進入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
#宿主機執(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
}
}
-
宿主機安裝Keepalived,實現(xiàn)雙機熱備
#宿主機執(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ù)
#進入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é)點永遠是Master裁赠,從節(jié)點永遠是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)下廓脆,在宿主機上直接關(guān)機畏浆,或者停止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)閉宿主機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ù)庫芋酌,僅憑這點知識還是遠遠不夠的。像我在PXC免費課中講到的雁佳,我們首先要有一個明確的知識體系脐帝,下一步就是做知識分解,一點點把技術(shù)拼圖給完成糖权。我見過非常多堵腹,東學(xué)一下,西學(xué)一下的人星澳,即便有10年的工作經(jīng)驗疚顷,依然難成大器。比如說前些年VR挺火的禁偎,現(xiàn)在區(qū)塊鏈技術(shù)也挺火的腿堤。我是個快要畢業(yè)的大學(xué)生,我想學(xué)這些技術(shù)幫我找一份好的工作如暖。其實這種想法不是不對笆檀,但是過于急功近利。我先把話題說的遠一點盒至,咱們一會兒再回來說技術(shù)規(guī)劃的事情酗洒。
? 在2013年士修,雷軍和董明珠打了個賭,如果小米在5年內(nèi)營業(yè)額超過格力樱衷,董明珠輸給雷軍10個億棋嘲,反之也是如此。兩家企業(yè)相比較矩桂,大家更看好雷軍的小米沸移。這是因為中國的制造業(yè)利潤太薄,制造業(yè)盈利存在上限的天花板侄榴,所以我們能準確預(yù)測出一家制造業(yè)企業(yè)未來的盈利空間阔籽。但是互聯(lián)網(wǎng)公司就不是這樣,想象空間太巨大牲蜀。比如說馬云的阿里巴巴笆制,從1999年創(chuàng)建,到2014年上市涣达,用了15年時間在辆。劉強東的京東商城,差不多也用了15年時間上市度苔。但是到了黃錚的拼多多這里匆篓,只用了3年時間就完成了上市,他還一舉超過劉強東寇窑,成為中國第六富豪鸦概。IT界一夜成名的還有滴滴打車的程維、美團的王興等等甩骏。
? 也正是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è)界認為會用VR讓HTC翻身鸥诽,可是到現(xiàn)在我們再也聽不到HTC這家公司的新聞了商玫』叮活著還是倒閉了牡借,我們都不知道,大家也不關(guān)心袭异。
? 所以我們選擇一個技術(shù)方向的時候钠龙,首先要看這個領(lǐng)域是不是有太多的水分,是不是有太多的熱錢御铃。比如今年3月的時候碴里,真格基金的徐小平發(fā)了一個微博說自己非常看好以太坊技術(shù)上真,于是短短時間咬腋,中國各家資本公司紛紛涌入?yún)^(qū)塊鏈領(lǐng)域。甚至還出現(xiàn)了2萬塊錢的區(qū)塊鏈講師速成班睡互,不管懂不懂計算機根竿,都能給你在短期內(nèi)培養(yǎng)成區(qū)塊鏈專家,然后你再去培訓(xùn)機構(gòu)忽悠人就珠,月薪兩萬寇壳,割學(xué)技術(shù)大學(xué)生的韭菜。我想妻怎,徐小平在微博上把區(qū)塊鏈捧到天上壳炎,何嘗不是一種資本炒作的手法呢。
? 最后說回到技術(shù)領(lǐng)域這塊逼侦。比如你是一個大學(xué)生匿辩,想投身一個有發(fā)展的技術(shù)方向,那么不妨拿起手機看看那些常用的APP上都用到了什么技術(shù)榛丢,這才是能落地能普及的撒汉。比如說刷抖音很容易上癮,上劃一條是你喜歡的視頻涕滋,再上劃一下睬辐,又是你感興趣的視頻。還有每個人打開淘寶APP宾肺,首頁的內(nèi)容都不一樣溯饵,都是你喜歡的商品,看什么東西都想賣锨用。淘寶也很絕丰刊,即使你不花錢買東西,只要你點擊看了一個你喜歡的商品增拥,從此以后啄巧,你各項愛好都被淘寶所感知了寻歧。這種技術(shù)是大數(shù)據(jù)上的協(xié)同過濾。說簡單一點秩仆,就是掌握了你很少資料的情況下码泛,去分析跟你有相同行為的人的喜好,于是推算出你的喜好澄耍。比如你點擊了某個牌子的運動鞋噪珊,那么淘寶的協(xié)同過濾就會計算購買了這個運動鞋的用戶,還買了什么東西齐莲,這些用戶共性的東西痢站,就是你的愛好。所以你再打開淘寶APP选酗,看到的都是你喜歡的東西阵难。抖音啊,今日頭條啊芒填,都是這樣的技術(shù)晌杰。所以你學(xué)大數(shù)據(jù)蓝晒,這個技術(shù)是能落地的醒串,太多產(chǎn)品在用這個技術(shù)了仔引。相比較而言,區(qū)塊鏈和人工智能就顯得太高冷了播玖。不是說技術(shù)不好椎工,但是距離大規(guī)模普及還是有很遠的距離。比如說區(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ù)和年齡都達不到要求了止后。所以我建議年輕人,參加工作以后溜腐,雖然崗位有界限译株,但是技術(shù)無界限。前端挺益、后臺歉糜、數(shù)據(jù)庫、原型設(shè)計望众、項目管理匪补,多少都要學(xué)一些,沒人教黍檩,就自己總結(jié)叉袍。只有技術(shù)全才,才能勝任技術(shù)團隊的管理者刽酱,才不會被企業(yè)淘汰喳逛。
? 其實我見過很多項目都是被不稱職的管理者給弄黃的。也許你也有同感棵里,這個項目A公司做過润文,B公司做過,現(xiàn)在客戶找到我們又要重做一版殿怜,這是為什么呢典蝌?項目開發(fā)的失敗率也太高了吧。這通常是項目管理者技術(shù)不過關(guān)導(dǎo)致的头谜,比如說A客戶去南方考察骏掀,覺得某公司的管理系統(tǒng)特別好,我想也做一套。于是找到了你截驮,A客戶是大老板笑陈,下面具體的業(yè)務(wù)細節(jié)說不太清楚,腦子里也沒有清晰的想法葵袭,反正想到什么就東一句涵妥、西一句的,然后你貿(mào)然選用了瀑布模型開發(fā)坡锡。經(jīng)過了需求分析蓬网、文檔設(shè)計,總算進入到了開發(fā)鹉勒。經(jīng)過兩個月的開發(fā)帆锋,終于可以拿出半成品給A客戶了,這時候A客戶說你做的不是他想要的東西贸弥,要不你推到重做把窟坐,要不我找別的公司去做海渊。然后別的公司做了绵疲,A客戶依然不滿意,于是開啟了無限的重做模式臣疑。
? 究其原因還是管理者用錯了開發(fā)模型盔憨,瀑布模型看似合理,但是問題在于編碼階段太靠后讯沈,等拿出半成品已經(jīng)小半年時間過去了郁岩。因此瀑布模型適用于那種能提出明確需求,而且到每一處細節(jié)的客戶缺狠。像A客戶這樣的人问慎,我們應(yīng)該用螺旋模型去開發(fā),小規(guī)募非眩快速迭代如叼,只開發(fā)最核心模塊,短期內(nèi)就拿出演示品跟客戶確認穷劈。這種小步快跑的策略適合提不出具體需求和需求不明確的場合笼恰。所以說,同學(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è)項目做砸了。呵呵梁沧,果然是這樣檀何。因為他們的團隊里缺少了技術(shù)方面的全才。僅靠專才是不能完成項目開發(fā)的廷支。我再舉一個例子频鉴,某公司的開發(fā)者老張,他是做后端比較擅長恋拍,因為工作年頭比較長了垛孔,于是就被提拔成了項目經(jīng)理。有一天施敢,日方客戶發(fā)來一封郵件周荐,說某模塊的業(yè)務(wù)流程要修改,看看中方這邊多長時間能實現(xià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ù)器
#進入r1節(jié)點 docker exec -it r1 bash cp /home/redis/redis.conf /usr/redis/redis.conf cd /usr/redis/src ./redis-server ../redis.conf #進入r2節(jié)點 docker exec -it r2 bash cp /home/redis/redis.conf /usr/redis/redis.conf cd /usr/redis/src ./redis-server ../redis.conf #進入r3節(jié)點 docker exec -it r3 bash cp /home/redis/redis.conf /usr/redis/redis.conf cd /usr/redis/src ./redis-server ../redis.conf #進入r4節(jié)點 docker exec -it r4 bash cp /home/redis/redis.conf /usr/redis/redis.conf cd /usr/redis/src ./redis-server ../redis.conf #進入r5節(jié)點 docker exec -it r5 bash cp /home/redis/redis.conf /usr/redis/redis.conf cd /usr/redis/src ./redis-server ../redis.conf #進入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
打包部署后端項目
-
進入人人開源后端項目卖局,執(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 #進入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 #進入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 #進入j1容器 docker exec -it j3 bash #啟動Java項目 nohup java -jar /home/soft/renren-fast.jar
-
安裝Nginx鏡像
docker pull nginx
-
創(chuàng)建Nginx容器染坯,配置負載均衡
宿主機上/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
宿主機上/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
#進入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 } }
#進入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目錄的文件拷貝到宿主機的/home/fn1/renren-vue、/home/fn2/renren-vue丘逸、/home/fn3/renren-vue的目錄下面
-
創(chuàng)建3節(jié)點的Nginx单鹿,部署前端項目
宿主機/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
宿主機/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
宿主機/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
-
配置負載均衡
宿主機/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
宿主機/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
-
配置雙機熱備
#進入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 } }
#進入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 } }
?