最近開始閱讀《Kubernetes權威指南》這本書,書上有一個單節點k8s的小例子,所以就跟着書上的步驟以及這篇博客http://lihaoquan.me/2017/2/25/create-kubernetes-single-node-mode.html操作了一遍,現在把這個過程記錄下來,對k8s有一個較直觀的認識。
這是一個簡單的Java Web應用,結構簡單,是一個運行在Tomcat里的Web App,JSP頁面通過JDBC直接訪問MySQL數據庫並展示數據。
此應用需要啟動兩個容器:Web App容器和MySQL容器,並且Web App容器需要訪問MySQL容器。
1.環境准備
這次實驗使用的環境是Centos7, IP地址為10.0.0.73
(1)yum源
剛開始我虛擬機的yum源是清華大學的,后面換了個阿里雲的yum源。我是為了和博客保持一致,不換源應該也是可以的(有待驗證)。
換源操作:
備份
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
下載新的CentOS-Base.repo到 /etc/yum.repos.d
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
最后運行
yum makecache
(2)關閉防火牆
centos7自帶firewall的防火牆業務,而k8s的master與工作node之間會有大量的網絡通信,安全的做法實在防火牆上配置各種需要相互通信的端口號,比如后面用到的3306,30001等端口。本文僅做一個學習過程,所以直接關閉防火牆服務。
systemctl disable firewalld.service
systemctl stop firewalld.service
2.安裝和配置k8s
(1)安裝etcd和k8s軟件(安裝過程中會自動安裝Docker軟件)
yum install -y etcd kubernetes
(2)配置修改
安裝完成后,需要修改相關配置
nano /etc/sysconfig/docker
將其中的OPTIONS的內容設置為:OPTIONS='--selinux-enabled=false --insecure-registry gcr.io'
nano /etc/kubernetes/apiserver
在KUBE_ADMISSION_CONTROL選項中去掉ServiceAccount選項。否則在后面的pod創建中,會報錯。
(3)切換docker hub鏡像源
為了穩定pull鏡像,使用Daocloud的鏡像服務
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://dbe35452.m.daocloud.io
(4)按順序啟動所有服務
systemctl start etcd
systemctl start docker
在啟動docker是遇到了如下錯誤:
運行命令查看docker服務
systemctl status docker.service
試了很多方法都不行后,在這個鏈接下面找到了答案https://segmentfault.com/q/1010000002392472。原來由於上面切換了docker hub源導致的問題。將/etc/docker/daemon.json中 {"registry-mirrors": ["http://34df6785.m.daocloud.io"],} 后面的逗號去掉就可以。
nano /etc/docker/daemon.json
繼續啟動剩下的服務
systemctl start kube-apiserver.service systemctl start kube-controller-manager.service systemctl start kube-scheduler.service systemctl start kubelet.service systemctl start kube-proxy.service
到目前為止,一個單機版的k8s環境就跑起來了。
3.啟動MySQL容器服務
(1)先拉去mysql的服務鏡像:
docker pull mysql
(2)啟動MySQL服務
首先為MySQL服務創建一個RC定義文件:mysql-rc.yaml。RC(Replication Controller)定義文件中有3個關鍵信息:
- 目標Pod的定義。
- 目標Pod需要運行的副本數量(Replicas)
- 要監控的目標Pod的標簽(Label),Label是Service和Pod之間的紐帶
apiVersion: v1 kind: ReplicationController #副本控制器RC metadata: name: mysql #RC的名稱,全局唯一 spec: replicas: 1 #Pod副本的期待數量 selector: app: mysql #符合目標的Pod擁有此標簽 template: #根據此模板創建Pod的副本(實例) metadata: labels: app: mysql #Pod副本擁有的標簽,對應RC的Selector spec: containers: #Pod內容器的定義部分 - name: mysql #容器的名稱 image: hub.c.163.com/library/mysql #容器對應的Docker image ports: - containerPort: 3306 #容器應用監聽的端口號 env: #注入容器內的環境變量 - name: MYSQL_ROOT_PASSWORD value: "123456"
創建好mysql-rc.yaml后,在master節點使用kubectl命令將它發布到k8s集群中。
kubectl create -f mysql-rc.yaml
接下來使用kubectl命令查看剛剛創建的RC:
使用下面命令查看Pod的創建情況:
可見Pod的狀態處於ContainerCreating,需要等到狀態為Runing才算成功。我在這里碰到了一個bug,Pod一直處在ContainerCreating狀態。博客http://blog.csdn.net/xts_huangxin/article/details/51130223提供了定位這種問題的方法。通過“kubectl describe pod PodName”指令查看pod發生的事件,從輸出中查看錯誤信息。我這邊的輸出是:
然后根據博客http://blog.csdn.net/learner198461/article/details/78036854提供的解決辦法,安裝rhsm(我也不知道這個是干什么的,就是紅帽的一個軟件)
yum install *rhsm*
然后再運行
kubectl delete -f mysql-rc.yaml
kubectl create -f mysql-rc.yaml
kubectl get pods
發現Pod已經跑起來了。
(3)創建關聯Service
最后,我們創建一個與之關聯的Kubernetes Service-MySQL的定義文件:mysql-svc.yaml
apiVersion: v1 kind: Service #表明是K8s Service metadata: name: mysql #Service的全局唯一名稱 spec: ports: - port: 3306 #Service提供服務的端口號 selector: #Service對應的Pod擁有這里定義的標簽 app: mysql
spec.selector確定了哪些Pod副本(實例)對應到本服務。類似地,我們通過kubectl create命令創建Service對象。
運行kubectl命令,創建service:
kubectl create -f mysql-svc.yaml
再運行如下狀態,查看剛剛創建的service:
kubectl get svc
注意到MySQL服務被分配到了一個值為10.254.152.247的Cluster IP地址,這是一個虛地址,隨后,k8s集群中其他新創建的Pod就可以通過Service的Cluster IP+端口號3306來連接和訪問它了。現在我們只需知道,根據Service的唯一名字,容器可以從環境變量中獲取到Service對應的Cluster IP地址和端口,從而發起TCP/IP連接請求了。
到這里,MySQL容器服務就啟動了。小結下創建過程,首先,拉取服務鏡像,然后創建RC定義文件,再發布到k8s中,可以看到pod被創建。最后創建一個與之關聯的k8s Service,也是通過.yaml文件和kubectl create命令創建。當然,這其中還牽扯到很多概念,比如說Pod和Service之間的聯系等等,這個要另起篇幅。
4.啟動Web容器服務
有了上面啟動MySQL容器服務的經驗,我們來啟動Web容器服務,過程是一樣的。
(1)先拉取一個測試鏡像到本地
docker pull kubeguide/tomcat-app:v1
(2)創建對應的RC文件myweb-rc.yaml,內容如下:
apiVersion: v1 kind: ReplicationController metadata: name: myweb spec: replicas: 5 #Pod副本期待數量為5 selector: app: myweb template: metadata: labels: app: myweb spec: containers: - name: myweb image: docker.io/kubeguide/tomcat-app:v1 ports: - containerPort: 8080 env: - name: MYSQL_SERVICE_HOST value: "mysql" - name: MYSQL_SERVICE_PORT value: "3306"
然后通過kubectl create命令完成RC的創建和驗證工作:
kubectl create -f myweb-rc.yaml
kubectl get rc
kubectl get pods
從輸出看到,在RC中聲明了5個Pod期待的數量,現在都已經建立並運行起來了,可以看出k8s在自動升級,擴容等方面帶來的優勢了。
(3)創建對應的Service
最后,創建對應的Service,以下是完整的yaml定義文件(myweb-svc.yaml):
apiVersion: v1 kind: Service metadata: name: myweb spec: type: NodePort ports: - port: 8080 nodePort: 30001 selector: app: myweb
type=NodePort和nodePort=30001的兩個屬性,表明此Service開啟了NodePort方式的外網訪問模式。在k8s集群之外,比如在本機的瀏覽器里,可以通過30001這個端口訪問myweb(對應到8080的虛端口上)。所以前面要關閉防火牆。
運行kubectl create命令進行創建:
kubectl create -f myweb-svc.yaml
最后,使用kubectl查看前面創建的Service
kubectl get services
5.驗證與總結
通過上面的幾個步驟,我們可以成功實現了一個簡單的k8s單機版例子。有兩種方法驗證我們的結果。
首先,可以在本機瀏覽器中輸入http://10.0.0.73:30001/demo/來測試我們發的web應用。然而,很不幸,報錯了:
報了一個JDBC連接的錯誤。如果網頁能打開的話,是有一個表格並且可以進行操作的。按書上的說法,看不到網頁有幾個原因:比如防火牆的問題,無法訪問30001端口,或者是因為通過代理上網的,瀏覽器錯把這個虛擬機的IP地址當成遠程地址了。所以有了第二種驗證方法,直接運行如下命令:
curl http://10.0.0.73:30001
輸出為:
我網上看其他教程也大都是采取這種方式驗證的,所以就這樣吧,雖然成就感小了一點,但畢竟還是跑起來了。重要的是對k8s有一個了解,學習使用它。
本文參考:
深入學習Kubernetes(一):單節點k8s安裝
《Kubernetes權威指南》
http://blog.csdn.net/xts_huangxin/article/details/51130223
https://segmentfault.com/q/1010000002392472
http://blog.csdn.net/learner198461/article/details/78036854