在kubernetes集群中創建redis主從多實例
繼續使用上次實驗環境 https://www.58jb.com/html/180.html ,因為環境中已經配置好flannel網絡了,接下要就是慢慢在此環境中創建一些實例。因為只是搭建簡單的環境是比較容易上手,隨便網上一搜可能就出來了。但是要自己去從頭一步一步跑起項目,還是基於真實的項目來跑的話還是需要自己多研究,當然目前還是止於使用階段,要深入還得多看資料。
本次要記錄的是自己從創建鏡像到實現redis主從示例,為什么要自己制作鏡像呢?其實就是為了自己可以學多點,畢竟網上的都人別人做好的,你自己沒做過根本不知道制作過程中會遇到什么。為什么有些鏡像大,有些鏡像比較小。這都是在哪里做的優化?
本次直接使用alpine基礎鏡像,因為它小,加上個redis也就11M左右的鏡像,如果使用centos可能就大點了,這里先不做存儲的方便,只是簡單的實現redis-master和redis-slave之間的自動發現。
為了自己好區分我直接制作兩個鏡像,一個為redis-master專門用來跑master服務的,一個為redis-slave專門跑slave實例的。其實可以只用一個,只需分兩個配置文件或者是兩個不同的啟動方法,這里不做這個介紹。
redis-slave鏡像制作
需要二個文件:Dockerfile、run.sh
Dockerfile內容如下:
FROM alpine:3.4
RUN apk add --no-cache redis sed bash
COPY run.sh /run.sh
CMD [ "/run.sh" ]
ENTRYPOINT [ "bash" ]
其實默認可以不使用redis.conf文件的,如果需要就在上面的Dockerfile文件也加入,這里目前也處於測試,先不加配置。
run.sh啟動腳本,也就是一行文件。
[root@k8s-node1 slave]# cat run.sh
#/bin/sh
redis-server --slaveof ${REDIS_MASTER_SERVICE_HOST} ${REDIS_MASTER_SERVICE_PORT}
打包成鏡像傳到內網倉庫:
docker build -t redis-slave .
docker tag redis-slave reg.docker.tb/harbor/redis-slave
docker push reg.docker.tb/harbor/redis-slave
redis-master鏡像制作
跟上面的配置差不多一樣,只是啟動時的命令有點不而已。
Dockerfile內容如下:
FROM alpine:3.4
RUN apk add --no-cache redis sed bash
COPY run.sh /run.sh
CMD [ "/run.sh" ]
ENTRYPOINT [ "bash" ]
其實默認可以不使用redis.conf文件的,如果需要就在上面的Dockerfile文件也加入,這里目前也處於測試,先不加配置。
run.sh啟動腳本,也就是一行文件。
[root@k8s-node1 master]# cat run.sh
#/bin/sh
redis-server
打包成鏡像傳到內網倉庫:
docker build -t redis-master .
docker tag redis-master reg.docker.tb/harbor/redis-master
docker push reg.docker.tb/harbor/redis-master
創建kube的配置文件yaml
創建一個master-service.yaml 來統一Master的入口,同時會自動關聯到labels為redis-master的所有Pod,這里要注意Service要優於pod啟動,不然無法通過環境變量把配置信息寫入到pod中。
apiVersion: v1
kind: Service
metadata:
name: redis-master
labels:
name: redis-master
spec:
ports:
- port: 6379
targetPort: 6379
selector:
name: redis-master
redis-master.yaml 以rc的方式來創建一個master容器,它會保證容器的副本數量。
apiVersion: v1
kind: ReplicationController
metadata:
name: redis-master
labels:
name: redis-master
spec:
replicas: 1
selector:
name: redis-master
template:
metadata:
labels:
name: redis-master
spec:
containers:
- name: master
image: reg.docker.tb/harbor/redis-master
ports:
- containerPort: 6379
redis-slave-service.yaml跟上面的Service一樣,都是管理redis-slave所有容器的,此服務創建后會把所有的slave實例的容器分配一個集群IP.
apiVersion: v1
kind: Service
metadata:
name: redis-slave
labels:
name: redis-slave
spec:
ports:
- port: 6379
selector:
name: redis-slave
redis-slave.yaml 同樣是以RC的方式來創建redis-slave實例,這里的數量為兩個。需要注意的是Image這里指定是剛才打包的鏡像名。
apiVersion: v1
kind: ReplicationController
metadata:
name: redis-slave
labels:
name: redis-slave
spec:
replicas: 2
selector:
name: redis-slave
template:
metadata:
labels:
name: redis-slave
spec:
containers:
- name: worker
image: reg.docker.tb/harbor/redis-slave
env:
- name: GET_HOSTS_FROM
value: env
#value: dns
ports:
- containerPort: 6379
注意:要實現master和slave服務自動發現,需要配置它們之間的對應關系。Kubernetes有兩種方法就是環境變量ENV和DNS記錄解析,因為我的實驗環境沒有使用這個DNS來解析,所以只能使用ENV環境變量。
上面的redis-slave.yaml 就是使用了env環境變量。
接下來創建實例吧:
master:
kubectl create -f redis-service.yaml
kubectl create -f redis-master.yaml
slave:
kubectl create -f redis-slave-service.yaml
kubectl create -f redis-slave.yaml
查看啟動的效果:
[root@k8s-master redis-pod]# kubectl get all -o wide
NAME READY STATUS RESTARTS AGE IP NODE
po/redis-master-qpzlh 1/1 Running 0 1h 172.21.2.2 k8s-node1
po/redis-slave-2rwk5 1/1 Running 0 1h 172.21.2.3 k8s-node1
po/redis-slave-6tf2f 1/1 Running 0 1h 172.21.8.3 k8s-node2
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
rc/redis-master 1 1 1 1h master reg.docker.tb/harbor/redis-master name=redis-master
rc/redis-slave 2 2 2 1h worker reg.docker.tb/harbor/redis-slave name=redis-slave
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
svc/kubernetes ClusterIP 10.254.0.1 <none> 443/TCP 3d <none>
svc/redis-master ClusterIP 10.254.152.116 <none> 6379/TCP 1h name=redis-master
svc/redis-slave ClusterIP 10.254.188.60 <none> 6379/TCP 1h name=redis-slave
簡單的測試master和slave是否可以同步數據:
連接master容器,可以看到有兩個Replication中有兩個connected_slaves就是從實例,后面跟着的就是IP地址。
[root@k8s-master redis-pod]# kubectl exec -it redis-master-qpzlh -- /bin/bash
bash-4.3# redis-cli
127.0.0.1:6379> info
# Server
redis_version:3.2.11
redis_git_sha1:535782f7
redis_git_dirty:0
redis_build_id:80ce8a1f388ac530
redis_mode:standalone
os:Linux 4.4.113-1.el7.elrepo.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:5.3.0
process_id:5
run_id:6629f021c2e5bd972fff05c84566cc92c7e59be0
tcp_port:6379
uptime_in_seconds:7105
uptime_in_days:0
......
# Clients
connected_clients:2
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
......
# Replication
role:master
connected_slaves:2
slave0:ip=172.21.2.3,port=6379,state=online,offset=5276,lag=1
slave1:ip=172.21.8.0,port=6379,state=online,offset=5276,lag=1
master_repl_offset:5276
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:5275
連接一個slave容器查看信息,可以看到Replication中role:slave為從實例,master的IP和端口等信息。
[root@k8s-master ~]# kubectl exec -it redis-slave-2rwk5 -- /bin/bash
bash-4.3# redis-cli
127.0.0.1:6379> info
# Server
redis_version:3.2.11
redis_git_sha1:535782f7
redis_git_dirty:0
redis_build_id:80ce8a1f388ac530
redis_mode:standalone
os:Linux 4.4.113-1.el7.elrepo.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:5.3.0
process_id:5
run_id:d48c42ea0a83babda663837ed5a6f9ef5a3ff9bf
tcp_port:6379
uptime_in_seconds:3957
uptime_in_days:0
......
# Replication
role:slave
master_host:10.254.152.116
master_port:6379
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:5542
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
此時在Master上創建一個key, 在slave上立馬就可以獲取到了。
master:
127.0.0.1:6379> set name swper
OK
slave:
127.0.0.1:6379> get name
"swper"
slave上只讀:
127.0.0.1:6379> set test 1
(error) READONLY You can't write against a read only slave.
這樣就實現了一主多從的效果了,集群的IP現在是外部無法訪問的,kubernetes節點中可以相互連通。
其實原本是很簡單的實驗,我居然在傳遞參數的時候少了個$號導致一直獲取不到