将近兩年多沒給大家更新文章了,今天晚上來點幹貨。總體來說19年到現在大環境不太好,各行各業都受影響,前段時間聽說蘇甯開啟全員賣貨模式,連副總裁都開始在朋友圈賣内褲了,哈哈哈,真是患難見忠臣啊,當然也聽說xx二手車強制轉崗、降薪,變相裁員。疫情期間讓員工主動離職,不給賠償,更可惡的是HR私自登入員工系統送出離職報告。我微信裡的一個做二手伺服器回收的老哥,18年收了兩千多萬的伺服器,去年一半都不到;還有的朋友,機關開不出來工資,生活也受到很大的影響。總而言之,我是比較幸運的,有穩定的工作,有時候也會做一些遊戲代練掙一些外快,反正吃飽飯是沒問題了,哈哈。
來說說自己的情況吧,2.3号回來就一直在工作,偶爾也會登入Boss直聘投投履歷,看看用人機關有哪些技能要求,但是很無奈,要麼多半是外包,要麼就是已讀不回,還有的拿了你的履歷就沒影了,曾經我手機上唯一的求職軟體,我也要解除安裝了。想想這些年,3584次溝通,投遞779份履歷,也算是給我的運維經曆畫上完美的句号了,如圖所示:

前一段時間正式開始啟用智聯招聘,哇,真的是讓我眼前一亮,以前不可以和HR溝通,現在也可以溝通了,而且每日簽到功能還有各種福利,例如履歷超級曝光、優先推薦、offer迷你吸鐵石、精美履歷模闆、超級面霸養成,而且你一投遞履歷,很快就有HR聯系你,總體體驗感是非常棒的,我也來說說我找工作的要求吧:1、距離超過35km不考慮(時間成本)2、外包不考慮(無歸屬感,福利待遇得不到保障)3、規模比較小的不考慮(有可能發不出工資,或者掐網線也是你負責哈哈)4、第一輪去直接技術面試,否則免談,跟你扯半天還不如實打實的來一場技術的碰撞。下圖是我在智聯招聘盲投5天的結果。
接下來咱們就開始聊技術吧,我把面試題發出來,大家參考一下:
1、git和svn 的差別
Git是分布式的,而Svn不是分布的
Git把内容按中繼資料方式存儲,而SVN是按檔案
Git沒有一個全局版本号,而SVN有:目前為止這是跟SVN相比Git缺少的最大的一個特征
Git的内容的完整性要優于SVN: GIT的内容存儲使用的是SHA-1雜湊演算法。這能確定代碼内容的完整性,確定在遇到磁盤故障和網絡問題時降低對版本庫的破壞
Git下載下傳下來後,在OffLine狀态下可以看到所有的Log,SVN不可以
SVN必須先Update才能Commit,忘記了合并時就會出現一些錯誤,git還是比較少的出現這種情況。
克隆一份全新的目錄以同樣擁有五個分支來說,SVN是同時複製5個版本的檔案,也就是說重複五次同樣的動作。而Git隻是擷取檔案的每個版本的 元素,然後隻載入主要的分支(master)在我的經驗,克隆一個擁有将近一萬個送出(commit),五個分支,每個分支有大約1500個檔案的 SVN,耗了将近一個小時!而Git隻用了區區的1分鐘!
版本庫(repository):SVN隻能有一個指定中央版本庫。當這個中央版本庫有問題時,所有工作成員都一起癱瘓直到版本庫維修完畢或者新的版本庫設立完成。而 Git可以有無限個版本庫。或者,更正确的說法,每一個Git都是一個版本庫,差別是它們是否擁有活躍目錄(Git Working Tree)。如果主要版本庫(例如:置於GitHub的版本庫)發生了什麼事,工作成員仍然可以在自己的本地版本庫(local repository)送出,等待主要版本庫恢複即可。工作成員也可以送出到其他的版本庫!
分支(Branch)在SVN,分支是一個完整的目錄。且這個目錄擁有完整的實際檔案。如果工作成員想要開啟新的分支,那将會影響“全世界”!每個人都會擁有和你一樣的分支。如果你的分支是用來進行破壞工作(安檢測試),那将會像傳染病一樣,你改一個分支,還得讓其他人重新切分支重新下載下傳,十分狗血。而 Git,每個工作成員可以任意在自己的本地版本庫開啟無限個分支。
Git的分支名是可以使用不同名字的。例如:我的本地分支名為OK,而在主要版本庫的名字其實是master。
送出(Commit)在SVN,當你送出你的完成品時,它将直接記錄到中央版本庫。當你發現你的完成品存在嚴重問題時,你已經無法阻止事情的發生了。如果網路中斷,你根本沒辦法送出!而Git的送出完全屬於本地版本庫的活動。而你隻需“推”(git push)到主要版本庫即可。Git的“推”其實是在執行“同步”(Sync)。
總結:SVN的特點是簡單,隻是需要一個放代碼的地方時用是OK的。
Git的特點版本控制可以不依賴網絡做任何事情,對分支和合并有更好的支援(當然這是開發者最關心的地方),不過想各位能更好使用它,需要花點時間嘗試一下。
2、mysql主從原理?主從不同步怎麼辦?主從慢,差的多咋辦?
master将改變記錄到二進制日志(binary log)中(這些記錄叫做二進制日志事件,binary log events)
slave将master的binary log events拷貝到它的中繼日志(relay log)
slave重做中繼日志中的事件,将改變反映它自己的資料。
或
從庫生成兩個線程,一個I/O線程,一個SQL線程;
i/o線程去請求主庫 的binlog,并将得到的binlog日志寫到relay log(中繼日志) 檔案中;
主庫會生成一個 log dump 線程,用來給從庫 i/o線程傳binlog;
SQL 線程,會讀取relay log檔案中的日志,并解析成具體操作,來實作主從的操作一緻,而最終資料一緻;
先上Master庫:
mysql>show processlist; 檢視下程序是否Sleep太多。發現很正常。
show master status; 也正常。
mysql> show master status;
+-------------------+----------+--------------+-------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+-------------------------------+
| mysqld-bin.000001 | 3260 | | mysql,test,information_schema |
+-------------------+----------+--------------+-------------------------------+
1 row in set (0.00 sec)
再到Slave上檢視
mysql> show slave status\G
Slave_IO_Running: Yes
Slave_SQL_Running: No
可見是Slave不同步
下面介紹兩種解決方法:
方法一:忽略錯誤後,繼續同步
該方法适用于主從庫資料相差不大,或者要求資料可以不完全統一的情況,資料要求不嚴格的情況
解決:
stop slave;
#表示跳過一步錯誤,後面的數字可變
set global sql_slave_skip_counter =1;
start slave;
之後再用mysql> show slave status\G 檢視:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
ok,現在主從同步狀态正常了。。。
方式二:重新做主從,完全同步
該方法适用于主從庫資料相差較大,或者要求資料完全統一的情況
解決步驟如下:
1.先進入主庫,進行鎖表,防止資料寫入
使用指令:
mysql> flush tables with read lock;
注意:該處是鎖定為隻讀狀态,語句不區分大小寫
2.進行資料備份
#把資料備份到mysql.bak.sql檔案
[root@server01 mysql]#mysqldump -uroot -p -hlocalhost > mysql.bak.sql
這裡注意一點:資料庫備份一定要定期進行,可以用shell腳本或者python腳本,都比較友善,確定資料萬無一失
3.檢視master 狀态
mysql> show master status;
+-------------------+----------+--------------+-------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+-------------------------------+
| mysqld-bin.000001 | 3260 | | mysql,test,information_schema |
+-------------------+----------+--------------+-------------------------------+
1 row in set (0.00 sec)
4.把mysql備份檔案傳到從庫機器,進行資料恢複
#使用scp指令
[root@server01 mysql]# scp mysql.bak.sql [email protected]:/tmp/
5.停止從庫的狀态
mysql> stop slave;
6.然後到從庫執行mysql指令,導入資料備份
mysql> source /tmp/mysql.bak.sql
7.設定從庫同步,注意該處的同步點,就是主庫show master status資訊裡的| File| Position兩項
change master to master_host = '192.168.128.100', master_user = 'rsync', master_port=3306, master_password='', master_log_file = 'mysqld-bin.000001', master_log_pos=3260;
8.重新開啟從同步
mysql> start slave;
9.檢視同步狀态
mysql> show slave status\G 檢視:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
好了,同步完成啦。
如果延遲比較大,就先确認以下幾個因素:
1.?從庫硬體比主庫差,導緻複制延遲
2.?主從複制單線程,如果主庫寫并發太大,來不及傳送到從庫,就會導緻延遲。更高版本的mysql可以支援多線程複制
3.?慢SQL語句過多
4.?網絡延遲5.?master負載
主庫讀寫壓力大,導緻複制延遲,架構的前端要加buffer及緩存層6.?slave負載
一般的做法是,使用多台slave來分攤讀請求,再從這些slave中取一台專用的伺服器,隻作為備份用,不進行其他任何操作.
另外,?2個可以減少延遲的參數:
–slave-net-timeout=seconds?機關為秒?預設設定為?3600秒
#參數含義:當slave從主資料庫讀取log資料失敗後,等待多久重建立立連接配接并擷取資料
–master-connect-retry=seconds?機關為秒?預設設定為?60秒
#參數含義:當重建立立主從連接配接時,如果連接配接建立失敗,間隔多久後重試。
通常配置以上2個參數可以減少網絡問題導緻的主從資料同步延遲
MySQL資料庫主從同步延遲解決方案
最簡單的減少slave同步延時的方案就是在架構上做優化,盡量讓主庫的DDL快速執行。還有就是主庫是寫,對資料安全性較高,比如sync_binlog=1,innodb_flush_log_at_trx_commit
=?1?之類的設定,而slave則不需要這麼高的資料安全,完全可以講sync_binlog設定為0或者關閉binlog,innodb_flushlog也可以設定為0來提高sql的執行效率。另外就是使用比主庫更好的硬體裝置作為slave。
3、kafka 和 mq 的差別
作為消息隊列來說,企業中選擇mq的還是多數,因為像Rabbit,Rocket等mq中間件都屬于很成熟的産品,性能一般但可靠性較強,
而kafka原本設計的初衷是日志統計分析,現在基于大資料的背景下也可以做營運資料的分析統計,而redis的主要場景是記憶體資料庫,作為消息隊列來說可靠性太差,而且速度太依賴網絡IO,在伺服器本機上的速度較快,且容易出現資料堆積的問題,在比較輕量的場合下能夠适用。
RabbitMQ,遵循AMQP協定,由内在高并發的erlanng語言開發,用在實時的對可靠性要求比較高的消息傳遞上。
kafka是Linkedin于2010年12月份開源的消息釋出訂閱系統,它主要用于處理活躍的流式資料,大資料量的資料處理上。
4、k8s service類型?
ClusterIP
叢集内部容器通路位址,會生成一個虛拟IP 與pod不在一個網段。
**NodePort **
會在主控端上映射一個端口,供外部應用通路模式。
**Headless CluserIP **
無頭模式,無serviceip,即把spec.clusterip設定為None 。
LoadBalancer
使用外部負載均衡。
5、pod之間如何通信?
pod内部容器之間
這種情況下容器通訊比較簡單,因為k8s pod内部容器是共享網絡空間的,是以容器直接可以使用localhost通路其他容器。
k8s在啟動容器的時候會先啟動一個pause容器,這個容器就是實作這個功能的。
pod 與 pod 容器之間
這種類型又可以分為兩種情況:
兩個pod在一台主機上面
兩個pod分布在不同主機之上
針對第一種情況,就比較簡單了,就是docker預設的docker網橋互連容器。
第二種情況需要更為複雜的網絡模型了,k8s官方推薦的是使用flannel組建一個大二層扁平網絡,pod的ip配置設定由flannel統一配置設定,通訊過程也是走flannel的網橋。
6、k8s健康檢查方式
存活性探針(liveness probes)和就緒性探針(readiness probes)
使用者通過 Liveness 探測可以告訴 Kubernetes 什麼時候通過重新開機容器實作自愈;Readiness 探測則是告訴 Kubernetes 什麼時候可以将容器加入到 Service 負載均衡池中,對外提供服務。文法是一樣的。
7、k8s pod狀态
Pod --Pending狀态
Pending 說明 Pod 還沒有排程到某個 Node 上面。可以通過
kubectl describe pod <pod-name> 指令檢視到目前 Pod 的事件,進而判斷為什麼沒有排程。可能的原因包括
資源不足,叢集内所有的 Node 都不滿足該 Pod 請求的 CPU、記憶體、GPU 等資源
HostPort 已被占用,通常推薦使用 Service 對外開放服務端口
Pod --Waiting 或 ContainerCreating狀态
首先還是通過 kubectl describe pod <pod-name> 指令檢視到目前 Pod 的事件。可能的原因包括
鏡像拉取失敗,比如配置了鏡像錯誤、Kubelet 無法通路鏡像、私有鏡像的密鑰配置錯誤、鏡像太大,拉取逾時等
CNI 網絡錯誤,一般需要檢查 CNI 網絡插件的配置,比如無法配置 Pod 、無法配置設定 IP 位址
容器無法啟動,需要檢查是否打包了正确的鏡像或者是否配置了正确的容器參數
Pod -- ImagePullBackOff狀态
這也是我們測試環境常見的,通常是鏡像拉取失敗。這種情況可以使用 docker pull <image> 來驗證鏡像是否可以正常拉取。
或者docker images | grep <images>檢視鏡像是否存在(系統有時會因為資源問題自動删除一部分鏡像),
Pod -- CrashLoopBackOff狀态
CrashLoopBackOff 狀态說明容器曾經啟動了,但可能又異常退出了。此時可以先檢視一下容器的日志
kubectl logs <pod-name> kubectl logs --previous <pod-name>
這裡可以發現一些容器退出的原因,比如
容器程序退出
健康檢查失敗退出
Pod --Error 狀态
通常處于 Error 狀态說明 Pod 啟動過程中發生了錯誤。常見的原因包括
依賴的 ConfigMap、Secret 或者 PV 等不存在
請求的資源超過了管理者設定的限制,比如超過了 LimitRange 等
違反叢集的安全政策,比如違反了 PodSecurityPolicy 等
容器無權操作叢集内的資源,比如開啟 RBAC 後,需要為 ServiceAccount 配置角色綁定
Pod --Terminating 或 Unknown 狀态
從 v1.5 開始,Kubernetes 不會因為 Node 失聯而删除其上正在運作的 Pod,而是将其标記為 Terminating 或 Unknown 狀态。想要删除這些狀态的 Pod 有三種方法:
從叢集中删除該 Node。使用公有雲時,kube-controller-manager 會在 VM 删除後自動删除對應的 Node。而在實體機部署的叢集中,需要管理者手動删除 Node(如 kubectl delete node <node-name>。
Node 恢複正常。Kubelet 會重新跟 kube-apiserver 通信确認這些 Pod 的期待狀态,進而再決定删除或者繼續運作這些 Pod。
使用者強制删除。使用者可以執行 kubectl delete pods <pod> --grace-period=0 --force 強制删除 Pod。除非明确知道 Pod 的确處于停止狀态(比如 Node 所在 VM 或實體機已經關機),否則不建議使用該方法。
特别是 StatefulSet 管理的 Pod,強制删除容易導緻腦裂或者資料丢失等問題。
Pod -- Evicted狀态
出現這種情況,多見于系統記憶體或硬碟資源不足,可df-h檢視docker存儲所在目錄的資源使用情況,如果百分比大于85%,就要及時清理下資源,尤其是一些大檔案、docker鏡像。
8、k8s資源限制
對于一個pod來說,資源最基礎的2個的名額就是:CPU和記憶體。
Kubernetes提供了個采用requests和limits 兩種類型參數對資源進行預配置設定和使用限制。
limit 會限制pod的資源利用:
當pod 記憶體超過limit時,會被oom。
當cpu超過limit時,不會被kill,但是會限制不超過limit值。
9、軟連結和硬連結差別
軟連接配接,其實就是建立立一個檔案,這個檔案就是專門用來指向别的檔案的(那就和windows 下的快捷方式的那個檔案有很接近的意味)。軟連結産生的是一個新的檔案,但這個檔案的作用就是專門指向某個檔案的,删了這個軟連接配接檔案,那就等于不需要這個連接配接,和原來的存在的實體原檔案沒有任何關系,但删除原來的檔案,則相應的軟連接配接不可用(cat那個軟連結檔案,則提示“沒有該檔案或目錄“)
硬連接配接是不會建立inode的,他隻是在檔案原來的inode link count域再增加1而已,也是以硬連結是不可以跨越檔案系統的。相反是軟連接配接會重建立立一個inode,當然inode的結構跟其他的不一樣,他隻是一個指明源檔案的字元串資訊。一旦删除源檔案,那麼軟連接配接将變得毫無意義。而硬連結删除的時候,系統調用會檢查inode link count的數值,如果他大于等于1,那麼inode不會被回收。是以檔案的内容不會被删除。
硬連結實際上是為檔案建一個别名,連結檔案和原檔案實際上是同一個檔案。可以通過ls -i來檢視一下,這兩個檔案的inode号是同一個,說明它們是同一個檔案;而軟連結建立的是一個指向,即連結檔案内的内容是指向原檔案的指針,它們是兩個檔案。
軟連結可以跨檔案系統,硬連結不可以;
軟連結可以對一個不存在的檔案名(filename)進行連結(當然此時如果你vi這個軟連結檔案,linux會自動建立一個檔案名為filename的檔案),硬連結不可以(其檔案必須存在,inode必須存在);
軟連結可以對目錄進行連接配接,硬連結不可以。
兩種連結都可以通過指令 ln 來建立。ln 預設建立的是硬連結。
使用 -s 開關可以建立軟連結
10、mount永久挂載
vi /etc/fstab
UUID=904C23B64C23964E /media/aborn/data ntfs defaults 0 2
其中第一列為UUID, 第二列為挂載目錄(該目錄必須為空目錄,必須存在),第三列為檔案系統類型,第四列為參數,第五列0表示不備份,最後一列必須為2或0(除非引導分區為1)
11、列印一個目錄下所有包含字元串A的行
例如/目錄
grep -rn "A" ./
或
find ./ -name "*.*" | xargs grep "A"
12、Kill掉所有包含服務名a的程序(xargs指令)
例如a程序
ps -ef | grep "^a" | grep -v grep | cut -c 9-15 | xargs kill -9
或
ps x | grep a | grep -v grep | awk '{print $1}' | xargs kill -9
13、談下對systemctl了解
Linux 服務管理兩種方式service和systemctl
systemd是Linux系統最新的初始化系統(init),作用是提高系統的啟動速度,盡可能啟動較少的程序,盡可能更多程序并發啟動。
systemd對應的程序管理指令是systemctl
systemctl指令相容了service, systemctl指令管理systemd的資源Unit
14、談下對IPtables的了解
iptables其實不是真正的防火牆,我們可以把它了解成一個用戶端代理,使用者通過iptables這個代理,将使用者的安全設定執行到對應的"安全架構"中,這個"安全架構"才是真正的防火牆,這個架構的名字叫netfilter
iptables其實是一個指令行工具,位于使用者空間,我們用這個工具操作真正的架構。
是以說,雖然我們使用service iptables start啟動iptables"服務",但是其實準确的來說,iptables并沒有一個守護程序,是以并不能算是真正意義上的服務,而應該算是核心提供的功能。
iptables有4表5鍊:
filter表——過濾資料包
Nat表——用于網絡位址轉換(IP、端口)
Mangle表——修改資料包的服務類型、TTL、并且可以配置路由實作QOS
Raw表——決定資料包是否被狀态跟蹤機制處理
INPUT鍊——進來的資料包應用此規則鍊中的政策
OUTPUT鍊——外出的資料包應用此規則鍊中的政策
FORWARD鍊——轉發資料包時應用此規則鍊中的政策
PREROUTING鍊——對資料包作路由選擇前應用此鍊中的規則(所有的資料包進來的時侯都先由這個鍊處理)
POSTROUTING鍊——對資料包作路由選擇後應用此鍊中的規則(所有的資料包出來的時侯都先由這個鍊處理)
15、給做好的鏡像添加一個檔案
用UltraISO PE (光軟碟通)軟體打開iso鏡像檔案就可以填加了
16、頁面無法通路排查思路
場景一:無錯誤狀态碼
無錯誤狀态碼,多數情況下是“ERR_CONNECTION_TIMED_OUT”問題。
出現ERR_CONNECTION_TIMED_OUT錯誤原因,可以總結為以下5點:
伺服器帶寬跑滿、存在***
若是雲伺服器可能存在賬号處于欠費狀态
服務沒有啟動
端口沒有正常監聽
防火牆或者防火牆政策限制
排查思路說明:
1、使用指令telnet IP Port 進行測試
2、如果端口是通的,則排查
檢視伺服器帶寬是否跑滿、是否有***
是否使用的賬号處于欠費狀态
3、如果端口不通,則排查
web服務沒有正常啟動
端口沒有正常監聽
防火牆/安全組攔截
若是web服務沒有正常啟動,需要啟動服務
若是端口沒有正常監聽,需要修改配置檔案
若是防火牆攔截,需要關閉防火牆進行測試,或者找到相關限制規則進行修改。
場景二:網站通路異常代碼4XX。
排查思路:
通過檢視其配置檔案,并檢測其配置檔案文法,發現文法正常;
通過指令行檢視其web服務端口運作正常,沒有程序僵屍狀況;
具體讀配置檔案,然後再查找客戶客戶配置檔案所指定的具體目錄;例如:網站資料目錄等(本案例是客戶機器遷移之後,由于阿裡磁盤的特性導緻盤符改變,客戶的資料盤挂載不上,etcfstab和盤符不比對)
問題定位到之後,重新以正确的方式挂載客戶網站資料;重新開機服務,問題得以圓滿解決;
基于類似問題還可以關注下目錄權限等問題。
經驗彙總:
針對網站通路報錯問題幾點排查建議:
伺服器配置檔案權限,以及文法的正确性;
配置檔案中指定的網站相關目錄存在問題,及相關權限問題;
運作web服務的使用者和相關權限問題;
防火牆的設定問題,導緻服務不可達;
伺服器服務程序僵死問題;
配置檔案中的非法字元問題;(特别是從windows平台直接cp過來的配置檔案容易報錯)這樣的問題較難排查,可以通過type 指令或者 file 指令檢視檔案類型;最好是二進制格式或者 ascii 碼,linux平台可以安裝 dos2unix 解決;
伺服器的錯誤日志亦是非常關鍵的問題突破口;
案例:報錯“404 Not Found”
問題原因:
404報錯的具體原因是通路的路徑url目錄在服務上沒有找到,如果直接使用ip或者域名通路,那麼實際通路的頁面是站點根目錄下的預設檔案(配置檔案中index後指定的檔案),如果伺服器上站點根目錄上沒有這個檔案,則會出現404錯誤。
排查步驟:
測試環境:Nginx環境
站點跟目錄/www/下沒有預設index.html檔案,通路ip/inde.html,會報Not Found錯誤。
備注:Apache環境下,404錯誤也是同樣的原理進行排查。
17、k8s中service什麼含義,怎麼用
Service是一種抽象的對象,它定義了一組Pod的邏輯集合和一個用于通路它們的政策,一個Serivce下面包含的Pod集合一般是由Label Selector來決定的。假如我們後端運作了3個副本,這些副本都是可以替代的,因為前端并不關心它們使用的是哪一個後端服務。盡管由于各種原因後端的Pod集合會發生變化,但是前端卻不需要知道這些變化,也不需要自己用一個清單來記錄這些後端的服務,Service的這種抽象就可以幫我們達到這種解耦的目的。
service 為後端pod提供一組負載均衡代理
三種IP:
Node IP:Node節點的IP位址
Pod IP:Pod的IP位址
Cluster IP:Service的IP位址
首先,Node IP是Kubernetes叢集中節點的實體網卡IP位址(一般為内網),所有屬于這個網絡的伺服器之間都可以直接通信,是以Kubernetes叢集外要想通路Kubernetes叢集内部的某個節點或者服務,肯定得通過Node IP進行通信(這個時候一般是通過外網IP了)
然後Pod IP是每個Pod的IP位址,它是Docker Engine根據docker0網橋的IP位址段進行配置設定的(我們這裡使用的是flannel這種網絡插件保證所有節點的Pod IP不會沖突)
最後Cluster IP是一個虛拟的IP,僅僅作用于Kubernetes Service這個對象,由Kubernetes自己來進行管理和配置設定位址,當然我們也無法ping這個位址,他沒有一個真正的實體對象來響應,他隻能結合Service Port來組成一個可以通信的服務。
定義Service
定義Service的方式和各種資源對象的方式類型一樣,假定我們有一組Pod服務,它們對外暴露了 80 端口,同時都被打上了app=myapp這樣的标簽,那麼我們就可以像下面這樣來定義一個Service對象:
pod示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: test
spec:
selector:
matchLabels:
app: myapp
replicas: 3
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
service基于pod的示例:
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 80
然後通過的使用kubectl create -f myservice.yaml就可以建立一個名為myservice的Service對象,它會将請求代理到使用 TCP 端口為 80,具有标簽app=myapp的Pod上,這個Service會被系統配置設定一個我們上面說的Cluster IP,該Service還會持續的監聽selector下面的Pod,會把這些Pod資訊更新到一個名為myservice的Endpoints對象上去,這個對象就類似于我們上面說的Pod集合了。
需要注意的是,Service能夠将一個接收端口映射到任意的targetPort。 預設情況下,targetPort将被設定為與port字段相同的值。 可能更有趣的是,targetPort 可以是一個字元串,引用了 backend Pod 的一個端口的名稱。 因實際指派給該端口名稱的端口号,在每個 backend Pod 中可能并不相同,是以對于部署和設計 Service ,這種方式會提供更大的靈活性。
另外Service能夠支援 TCP 和 UDP 協定,預設是 TCP 協定。
kube-proxy
在Kubernetes叢集中,每個Node會運作一個kube-proxy程序, 負責為Service實作一種 VIP(虛拟 IP,就是我們上面說的clusterIP)的代理形式,現在的Kubernetes中預設是使用的iptables這種模式來代理。這種模式,kube-proxy會監視Kubernetes master對 Service 對象和 Endpoints 對象的添加和移除。 對每個 Service,它會添加上 iptables 規則,進而捕獲到達該 Service 的 clusterIP(虛拟 IP)和端口的請求,進而将請求重定向到 Service 的一組 backend 中的某一個個上面。 對于每個 Endpoints 對象,它也會安裝 iptables 規則,這個規則會選擇一個 backend Pod。
預設的政策是,随機選擇一個 backend。 我們也可以實作基于用戶端 IP 的會話親和性,可以将 service.spec.sessionAffinity 的值設定為 "ClientIP" (預設值為 "None")。
另外需要了解的是如果最開始選擇的 Pod 沒有響應,iptables 代理能夠自動地重試另一個 Pod,是以它需要依賴 readiness probes。
Service 類型
在定義Service的時候可以指定一個自己需要的類型的Service,如果不指定的話預設是ClusterIP類型。
可以使用的服務類型如下:
1、ClusterIP:通過叢集的内部 IP 暴露服務,選擇該值,服務隻能夠在叢集内部可以通路,這也是預設的ServiceType。
2、NodePort:通過每個 Node 節點上的 IP 和靜态端口(NodePort)暴露服務。NodePort 服務會路由到 ClusterIP 服務,這個 ClusterIP 服務會自動建立。通過請求 :,可以從叢集的外部通路一個 NodePort 服務。
3、LoadBalancer:使用雲提供商的負載局衡器,可以向外部暴露服務。外部的負載均衡器可以路由到 NodePort 服務和 ClusterIP 服務,這個需要結合具體的雲廠商進行操作。
4、ExternalName:通過傳回 CNAME 和它的值,可以将服務映射到 externalName 字段的内容(例如, foo.bar.example.com)。沒有任何類型代理被建立,這隻有 Kubernetes 1.7 或更高版本的 kube-dns 才支援。
NodePort 類型
如果設定 type 的值為 "NodePort",Kubernetes master 将從給定的配置範圍内(預設:30000-32767)配置設定端口,每個 Node 将從該端口(每個 Node 上的同一端口)代理到 Service。該端口将通過 Service 的 spec.ports[*].nodePort 字段被指定,如果不指定的話會自動生成一個端口。
需要注意的是,Service 将能夠通過 :spec.ports[].nodePort 和 spec.clusterIp:spec.ports[].port 而對外可見。
接下來建立一個NodePort的服務
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
selector:
app: myapp
type: NodePort
ports:
- protocol: TCP
port: 80
targetPort: 80
name: myapp-http
nodePort: 32560
建立該Service:
$ kubectl create -f service-demo.yaml
然後我們可以檢視Service對象資訊:
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 27d
myservice NodePort 10.104.57.198 <none> 80:32560/TCP 14h
可以看到myservice的 TYPE 類型已經變成了NodePort,後面的PORT(S)部分也多了一個 32560 的随機映射端口。
ExternalName
ExternalName 是 Service 的特例,它沒有 selector,也沒有定義任何的端口和 Endpoint。 對于運作在叢集外部的服務,它通過傳回該外部服務的别名這種方式來提供服務。
kind: Service
apiVersion: v1
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
當查詢主機 my-service.prod.svc.cluster.local 時,叢集的 DNS 服務将傳回一個值為 my.database.example.com 的 CNAME 記錄。 通路這個服務的工作方式與其它的相同,唯一不同的是重定向發生在 DNS 層,而且不會進行代理或轉發。 如果後續決定要将資料庫遷移到 Kubernetes 叢集中,可以啟動對應****的 Pod,增加合适的 Selector 或 Endpoint,修改 Service 的 type,完全不需要修改調用的代碼,這樣就完全解耦了。
18、和K8s服務端口沖突了怎麼處理
k8s端口被占用報錯執行以下指令:
kubeadm reset
19、redhat 6.X版本系統 和 centos 7.X版本有啥差別?
筆者回答:桌面系統(6/GNOE2.x、7/GNOME3.x)、檔案系統(6/ext4、7/xfs)、核心版本(6/2.6x、7/3.10x)、防火牆(6/iptables、7/firewalld)、預設資料庫(6/mysql、7/mariadb)、啟動服務(6/service啟動、7/systemctl啟動)、網卡(6/eth0、7/ens192)等。
20、說一下你們公司怎麼發版的(代碼怎麼釋出的)?
jenkins配置好代碼路徑(SVN或GIT),然後拉代碼,打tag。需要編譯就編譯,編譯之後推送到釋出伺服器(jenkins裡面可以調腳本),然後從分發伺服器往下分發到業務伺服器上。如果是php的項目,可以rsync上線,但是php也可以用Jenkins來操作,php7之後也是支援編譯運作,這樣上線之後運作效率更快,而且一定程度上保證了代碼的安全。
前段時間,已經确定入職機關了,然後石墨文檔給我發來入職邀請,我何德何能啊,真的是很感動,以下是他們技術面試官對我的評價,哈哈,裝個13。