79

容器超融合的实现&持久存储的动态分配 : Openshift3.9学习系列第六终

 5 years ago
source link: http://www.10tiao.com/html/360/201807/2663488549/1.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

前言

本文仅代表作者的个人观点;

本文的内容仅限于技术探讨,不能直接作为指导生产环境的素材;

本文素材是红帽公司产品技术和手册;

本文分为系列文章,一共六篇,本文是第五篇。


第一篇:

Openshift3.9高可用部署考虑点1

第二篇:

干货巨献:Openshift3.9的网络管理大全.加长篇---Openshift3.9学习系列第二篇

第三篇:

身份验证和权限管理---Openshift3.9学习系列第三篇

第四篇:

容器计算资源管理&网络QoS的实现---Openshift3.9学习系列第四篇

第五篇:

厉害了!全CI/CD工具链的实现 | 基于OCP离线: Openshift3.9学习系列第五篇




一、容器原生存储


CNS:container native storage,容器原生存储。OCP的容器原生存储使用glusterfs。

针对Openshift的应用场景,我们对GlusterFS、Ceph RBD以及NFS的优缺点进行分析:


   对比项 Ceph RBD Glusterfs SAN+NFS Openshift平台容器数据持久化的支持 支持Pod级的动态创建,不支持ReadWriteMany
   当Kubernetes运行在OpenStack上时,它是最好的存储
   
   
支持动态分配
   支持ReadWriteOnce和ReadWriteMany
   
   Container Native Storage
   
静态支持,手动和静态预先支持,空间分配低效,容器级别安全性有待提升
   普遍使用的,易于设置PoC,易于理解
   支持ReadWriteOnce和ReadWriteMany
   
高可用 Ceph系统提供了对象、块、和文件存储功能,使用CRUSH算法维护存储对象与存储服务器的对应关系,无Master设计。对象复制,集群扩容,数据迁移,故障检测和处理等复杂功能由Ceph  OSD(Object Storage  Device)提供,避免了单点失败 Glusterfs开源的分布式文件系统,没有元数据服务器层,存储使用弹性哈希算法来查找存储池中的数据(通过文件名来计算哈希值),从而消除了单点故障和导致 I/O 瓶颈的常见根源和故障多发情况 依赖于存储硬件和NFS 数据保护 Ceph  OSD 守护进程自动在其它 Ceph 节点上创建对象副本来确保数据安全和高可用性,存储池快照 数据分布与跨节点的多个bricks,支持在线卷快照(Volume Snapshot),可恢复镜像时间点数据,同时支持跨区域(WLAN)的异步主备份卷复制 依赖于存储硬件RAID、快照、和复制 扩展性能 可以动态添加节点和硬盘 可以动态增加或缩减数据存储池和节点 可以动态增加或缩减数据存储池,依赖于存储硬件 caching/分层存储能力 支持,比如:ssd盘组成的缓冲层(IO性能要求高的应用)而相对低速、便宜的设备,作为经济存储层(IO性能要求低) 支持,比如:ssd盘组成的缓冲层(IO性能要求高的应用)而相对低速、便宜的设备,作为经济存储层(IO性能要求低) 支持,依赖于存储硬件 安装和管理 安装简单,维护较复杂 安装、维护简单 安装、维护简单 故障恢复 但节点失效时,自动迁移数据,重新复制副本 当节点、硬件、磁盘、网络故障时,系统能自动处理,无须管理员介入。 依赖于存储硬件 成本 硬件成本低 硬件成本低 硬件成本高


所以,建议用glusterfs与OCP配合使用。


OCP和Gluster的集成方式如下:


首先,gluster节点也是OCP的计算节点,通常是三个。

三个gluster节点上,每个节点运行一个glusterfs-storage pod,它是glusterfs的daemonSet。


除此之外,OCP和Gluster的集成,有个重要的组件heketi。


Heketi是一个具有resetful接口的glusterfs管理程序,作为kubernetes的Storage存储的external provisioner。Heketi提供了一个RESTful管理界面,可用于管理GlusterFS卷的生命周期。借助Heketi,像OpenStack Manila,Kubernetes和OpenShift这样的云服务可以动态地配置GlusterFS卷和任何支持的持久性类型。Heketi将自动确定整个集群的brick位置,确保将brick及其副本放置在不同的故障域中。Heketi还支持任意数量的GlusterFS集群,允许云服务提供网络文件存储,而不受限于单个GlusterFS集群。


OCP和gluster的集成方案中,将heketi用于大多数常见的卷管理操作,例如创建,删除和调整大小。 默认情况下,heketi将创建三副本的卷,即每个文件在三个不同节点上有三个副本的卷。 



参照下图:



而在OCP和Gluster的集成方案中,glusterfs-storage pod和Heketi都会运行到一个项目中:


除此之外,我们还需要在default项目中创建一个glusterfs的endpoint和一个service。

glusterfs的endpoint直接表明了glusterfs节点(node3、node4、node5)的IP

当一个新建的pod想使用glusterfs的资源的时候,需要在pv的描述中指明endpoint(后面会有详细介绍)。


使用这种方式的时候(使用默认的storage class),就需要手工先在glusterfs上创建一个volume,使用hetiki的cli创建。


如果我们想对存储动态管理,也就是说,我需要PV的时候,后台glusterfs自动创建对应的volume,那就需要自定义一个storage class,将它指明对hetiki API的调用。并且在pv和pvc的配置中指定storage class。


这样当我们申请pv的时候,glusterfs才通过hetiki在glusterfs上创建volume,一键式完成pv和glusterfs volume的创建。



、实验环境介绍


现有的一套OCP环境:

存储使用的是NFS方式:




   三、 OCP集群动态扩容


接下来,我们配置gluster。我们新增加三个节点,到OCP集群中,用于运行gluster。


修改ansible inventory文件,并将new_nodes子项添加到[OSEv3:children]部分。

 

vi /etc/ansible/hosts


增加[new_nodes]


[OSEv3:children]

lb

masters

etcd

nodes

nfs

#glusterfs

new_nodes



## These are CNS nodes

[new_nodes]


## These are CNS nodes

[new_nodes]

support1.b434.internal openshift_hostname=support1.b434.internal  openshift_node_labels="{'env':'glusterfs', 'cluster': 'b434'}"

support2.b434.internal openshift_hostname=support2.b434.internal  openshift_node_labels="{'env':'glusterfs', 'cluster': 'b434'}"

support3.b434.internal openshift_hostname=support3.b434.internal  openshift_node_labels="{'env':'glusterfs', 'cluster': 'b434'}"




[glusterfs]

support1.GUID.internal glusterfs_devices='[ "/dev/xvdd" ]'

support2.GUID.internal glusterfs_devices='[ "/dev/xvdd" ]'

support3.GUID.internal glusterfs_devices='[ "/dev/xvdd" ]'


需要注意的是,新增加节点的ovs插件策略,需要与现有集群一致(

redhat/openshift-ovs-networkpolicy):

每个Node上的配置文件:/etc/origin/node/node-config.yaml



执行预安装:

ansible-playbook  /usr/share/ansible/openshift-ansible/playbooks/prerequisites.yml


运行脚本进行OCP节点扩容:

ansible-playbook  /usr/share/ansible/openshift-ansible/playbooks/openshift-node/scaleup.yml


给三个节点增加label:

oc label node support1.b434.internal logging-infra-fluentd=true

oc label node support2.b434.internal logging-infra-fluentd=true

oc label node support3.b434.internal logging-infra-fluentd=true


扩容成功以后,将ansible inventory上的new_nodes删掉。




  四、gluster安装之前的准备工作


修改ansible inventory文件

[OSEv3:vars]

openshift_deployment_type=openshift-enterprise

openshift_master_cluster_method=native

openshift_master_cluster_hostname=loadbalancer1.b434.internal

openshift_master_cluster_public_hostname=loadbalancer.b434.example.opentlc.com

openshift_master_default_subdomain=apps.test.example.com

openshift_master_default_subdomain=apps.b434.example.opentlc.com

containerized=false

openshift_hosted_infra_selector='env=infra'

openshift_hosted_node_selector='env=app'

openshift_master_identity_providers=[{'name': 'ldap', 'challenge': 'true', 'logi                                                                             n': 'true', 'kind': 'LDAPPasswordIdentityProvider','attributes': {'id': ['dn'],                                                                              'email': ['mail'], 'name': ['cn'], 'preferredUsername': ['uid']}, 'bindDN': 'uid                                                                             =admin,cn=users,cn=accounts,dc=shared,dc=example,dc=opentlc,dc=com', 'bindPasswo                                                                             rd': 'r3dh4t1!', 'ca': '/etc/origin/master/ipa-ca.crt','insecure': 'false', 'url                                                                             ': 'ldaps://ipa.shared.example.opentlc.com:636/cn=users,cn=accounts,dc=shared,dc                                                                             =example,dc=opentlc,dc=com?uid?sub?(memberOf=cn=ocp-users,cn=groups,cn=accounts,                                                                             dc=shared,dc=example,dc=opentlc,dc=com)'}]

openshift_master_ldap_ca_file=/root/ipa-ca.crt

os_sdn_network_plugin_name='redhat/openshift-ovs-multitenant'

###########################################################################

### OpenShift GlusterFS Vars

###########################################################################


# CNS storage for applications

# openshift_storage_glusterfs_namespace=app-storage

openshift_storage_glusterfs_block_deploy=false


###########################################################################

### Ansible Vars

###########################################################################

timeout=60

ansible_become=yes

ansible_ssh_user=ec2-user


# disable memory check, as we are not a production environment

openshift_disable_check="memory_availability"


# Set this line to enable NFS

openshift_enable_unsupported_configurations=True



###########################################################################

### OpenShift Hosts

###########################################################################

[OSEv3:children]

lb

masters

etcd

nodes

nfs

glusterfs

[lb]

loadbalancer1.b434.internal


[masters]

master1.b434.internal

master2.b434.internal

master3.b434.internal


[etcd]

master1.b434.internal

master2.b434.internal

master3.b434.internal


[nodes]

## These are the masters

master1.b434.internal openshift_hostname=master1.b434.internal  openshift_node_l                                                                             abels="{'env': 'master', 'cluster': 'b434'}"

master2.b434.internal openshift_hostname=master2.b434.internal  openshift_node_l                                                                             abels="{'env': 'master', 'cluster': 'b434'}"

master3.b434.internal openshift_hostname=master3.b434.internal  openshift_node_l                                                                             abels="{'env': 'master', 'cluster': 'b434'}"


## These are infranodes

infranode1.b434.internal openshift_hostname=infranode1.b434.internal  openshift_                                                                             node_labels="{'env':'infra', 'cluster': 'b434'}"

infranode2.b434.internal openshift_hostname=infranode2.b434.internal  openshift_                                                                             node_labels="{'env':'infra', 'cluster': 'b434'}"


## These are regular nodes

node1.b434.internal openshift_hostname=node1.b434.internal  openshift_node_label                                                                             s="{'env':'app', 'cluster': 'b434'}"

node2.b434.internal openshift_hostname=node2.b434.internal  openshift_node_label                                                                             s="{'env':'app', 'cluster': 'b434'}"

node3.b434.internal openshift_hostname=node3.b434.internal  openshift_node_label                                                                             s="{'env':'app', 'cluster': 'b434'}"


## These are CNS nodes

support1.b434.internal openshift_hostname=support1.b434.internal  openshift_node                                                                             _labels="{'env':'glusterfs', 'cluster': 'b434'}"

support2.b434.internal openshift_hostname=support2.b434.internal  openshift_node                                                                             _labels="{'env':'glusterfs', 'cluster': 'b434'}"

support3.b434.internal openshift_hostname=support3.b434.internal  openshift_node                                                                             _labels="{'env':'glusterfs', 'cluster': 'b434'}"



[nfs]

support1.b434.internal openshift_hostname=support1.b434.internal


[glusterfs]

 support1.b434.internal glusterfs_devices='[ "/dev/xvdd" ]'

 support2.b434.internal glusterfs_devices='[ "/dev/xvdd" ]'

 support3.b434.internal glusterfs_devices='[ "/dev/xvdd" ]'



执行脚本,安装glusterfs:

ansible-playbook /usr/share/ansible/openshift-ansible/playbooks/openshift-glusterfs/config.yml


安装成功以后,OCP中会创建一个新的项目:glusterfs,里面有几个pod:

而这几个pod,只运行在指定的三个support节点上:


五、设置动态预配置


在本节中,我们将为GlusterFS和旧存储(NFS)设置包含存储类的动态预配置。默认情况下,GlusterFS安装程序会创建一个名为glusterfs-storage的存储类。我们将该存储类设置为默认值。我们可以为旧存储分配不同的存储类,并了解PVC绑定到非默认PV所需的特殊设置。最后,部署应用程序并记录它如何使用默认存储类,动态配置PV和PVC以分配存储。然后查看远程卷上的实际存储。


查看已经安装的存储类:



为应用创建一个新的存储类,叫development-storage,他就是一个动态分配的storage class,我们可以看到指明了调用heketi。

cat << EOF | oc create -f -

apiVersion: storage.k8s.io/v1

kind: StorageClass

metadata:

  name: development-storage

parameters:

  resturl: http://heketi-storage-glusterfs.apps.b434.example.opentlc.com

  restuser: admin

  secretName: heketi-storage-admin-secret

  secretNamespace: glusterfs

  volumenameprefix: "development"

provisioner: kubernetes.io/glusterfs

reclaimPolicy: Delete

EOF



为旧的NFS基础结构和uservol存储创建名为old-infra的存储类:

cat << EOF > old-infra.yml

kind: StorageClass

apiVersion: storage.k8s.io/v1

metadata:

  name: old-infra

provisioner: no-provisioning

parameters:

EOF

oc create -f old-infra.yml


用old-infra替换所有NFS PV的存储类:

oc get pv -o yaml | sed '/persistentVolumeReclaimPolicy/a \    storageClassName: old-infra' | oc replace -f -

检查:

通过将storageclass.kubernetes.io/is-default-class批注的值更改为true,将开发存储类设置为默认值:


oc patch storageclass development-storage -p '{"metadata": {"annotations": {"storageclass.kubernetes.io/is-default-class": "true"}}}'

请注意,开发存储存储类(动态分配的)现在是默认类。


部署示例应用程序并观察它是否使用默认存储类:


oc new-project smoke-test

oc new-app nodejs-mongo-persistent 

应用开始创建后,会创建pv,这时候pv定义的配置,调用heketi自动创建了glusterfs的volume:

被自动创建的pv如下,可以看出来是自动创建的:


oc get pvc


我们设置多个存储类的时候,也方便我们在创建pv的时候,根据需要进行选择:

很显然,动态分配的方式更灵活有效,更有生命力!


六、查看存储数据


登录一个pod,查看vol:


查看一个volume的详细信息:

sh-4.2# gluster vol info development_glusterfs_mongodb_e37f52c1-8652-11e8-9cd2-068204e4c046


Volume Name: development_glusterfs_mongodb_e37f52c1-8652-11e8-9cd2-068204e4c046

Type: Replicate

Volume ID: 29a559da-cb71-448e-ade6-1cf7d5e0f0e9

Status: Started

Snapshot Count: 0

Number of Bricks: 1 x 3 = 3

Transport-type: tcp

Bricks:

Brick1: 192.199.0.8:/var/lib/heketi/mounts/vg_e7b8320763dd4f5f2f4d331191d6c919/brick_9ac71e8944e165923a3e055a140dee42/brick

Brick2: 192.199.0.142:/var/lib/heketi/mounts/vg_7a4df0d142c82309861c38e8b641f487/brick_0d144473601c1902c1c4affbb7ecd234/brick

Brick3: 192.199.0.215:/var/lib/heketi/mounts/vg_f19f54b310e0e99cd24ce287795c5055/brick_680a4e0a80c34b1f79dd1c81600420a3/brick

Options Reconfigured:

transport.address-family: inet

nfs.disable: on

cluster.brick-multiplex: on


在上面的信息中:三个brick来源于三个support节点。


在pod中查看一个brick的内容,我们能够看到里面存放的文件:


七、 对docker-registry做存储迁移(采用静态创建pv方式)


在本小节中,我们将OCP的docker registry从NFS迁移到GlusterFS StorageClass以用于托管应用程序。



首先,创建Gluster服务和端点

在本节中,在default项目中创建Gluster service和endpoint。由于docker-registry集成容器注册表的关键特性,需要使用静态配置的卷来确保服务的配额,以保证访问和性能。


将GlusterFS作为静态持久卷访问的每个项目/命名空间(与上面的动态存储类相反)必须具有在该命名空间中为GlusterFS访问创建的OpenShift服务和端点对象。


oc project default


[root@master1 ~]# cat  /root/gluster-service-endpoints.yaml

apiVersion: v1

kind: Service

metadata:

  name: gluster-registry-service

spec:

  ports:

  - port: 1

---

apiVersion: v1

kind: Endpoints

metadata:

  name: gluster-registry-endpoints

subsets:

  - addresses:

      - ip: 192.199.0.142

    ports:

      - port: 1

  - addresses:

      - ip: 192.199.0.215

    ports:

      - port: 1

  - addresses:

      - ip: 192.199.0.8

    ports:

      - port: 1


从default项目中创建Gluster服务和端点对象:

 oc create -f gluster-service-endpoints.yaml

确认gluster的svc和endpoint已经成功创建:


手动配置GlusterFS卷

接下来,将使用heketi-cli为docker-registry手动设置GlusterFS存储卷。 需要为用于NFS docker-registry同一fsGroup创建此卷。


检查已经运行的docker-registry pod以确定要在GlusterFS卷中使用的正确fsGroup:

查看目前的id:1000000000



接下来,登录到 Heketipod:

设置环境变量,列出已经有的volume:

export HEKETI_CLI_KEY=$HEKETI_ADMIN_KEY

export HEKETI_CLI_USER=admin

heketi-cli volume list


使用上面确定的REGISTRY_GID为静态配置的注册表创建新卷:

heketi-cli volume create --size=20 --gid=1000000000 --name=gluster-registry-volume

使用SSH访问您的一个infra节点并切换到root以测试安装新创建的卷.


在infra1节点上,挂载volume的一个副本以确保组ID与请求的匹配:

export GUID=`hostname|awk -F. '{print $2}'`

echo $GUID

mkdir -p /mnt/glusterfs/gluster-registry-volume

mount -t glusterfs support1.$GUID.internal:/gluster-registry-volume /mnt/glusterfs/gluster-registry-volume/

命令行查看,新创建的gluster volume已经创建成功:


验证已mount目录的内容,并验证是否显示了正确的fsGroup,验证结果一致:

umount volume并清除挂载点:

umount /mnt/glusterfs/gluster-registry-volume

rmdir /mnt/glusterfs/gluster-registry-volume

rmdir /mnt/glusterfs



通过为docker-registry指示正确的accessModes和persistentVolumeReclaimPolicy以及GlusterFS的正确endpoints和path,为卷创建PV。

(需要一个gluster-registry-claim及其命名空间的claimRef,以便PVC不会绑定到不同的PV)


oc project default


cat << EOF | oc create -f -

apiVersion: v1

kind: PersistentVolume

metadata:

  name: gluster-registry-volume

spec:

  storageClassName: reg-gluster

  capacity:

    storage: 20Gi

  accessModes:

    - ReadWriteMany

  glusterfs:

    endpoints: gluster-registry-endpoints

    path: gluster-registry-volume

    readOnly: false

  claimRef:

    name: gluster-registry-claim

    namespace: default

  persistentVolumeReclaimPolicy: Retain

EOF


oc get pv gluster-registry-volume



创建PVC:

此PVC的名称和命名空间与上面PV中的claimRef中的名称和命名空间相匹配。


我们还需要通过指示正确的volumeName和storageClassName来将PVC与PV匹配。

cat << EOF | oc create -f -

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

  name: gluster-registry-claim

spec:

  accessModes:

  - ReadWriteMany

  volumeName: gluster-registry-volume

  storageClassName: ""

  resources:

     requests:

       storage: 20Gi

EOF




八、备份注册表中的现有容器映像


从现有的基于NFS的注册表卷备份现有容器映像。


使用oc rsync将注册表文件系统的内容复制到堡垒上的目录中:



修改卷定义并重新部署。

使用新存储修改注册表部署配置中的卷定义,然后重新部署注册表。


使用新的GlusterFS支持的卷替换旧版(NFS)卷,并允许注册表使用新存储重新部署:

oc volume dc/docker-registry --add --overwrite --name=registry-storage -m /registry -t pvc --claim-name=gluster-registry-claim



使用oc describe dc / docker-registry验证docker registry 存储卷现在是否正在使用gluster-registry-claim pvc。


登录docker-registry所在的infranode,查看gluster volume已经mount到本节点:



使用oc rsync将docker-registry的先前内容还原到新的持久卷中:

以karla身份登录并使用skopeo验证更改:

oc login -u karla -p r3dh4t1!

yum -y install skopeo

oc adm policy add-cluster-role-to-user cluster-admin karla

skopeo --debug inspect --creds karla:$(oc whoami -t) --tls-verify=false docker://docker-registry-default.apps.$GUID.example.opentlc.com/openshift/dotnet



测试能够向docker-Registry成功push镜像。


oc login -u karla -p r3dh4t1!

docker login -u openshift -p $(oc whoami -t) docker-registry.default.svc:5000

docker pull docker.io/busybox

docker tag docker.io/busybox docker-registry.default.svc:5000/openshift/busybox

docker push docker-registry.default.svc:5000/openshift/busybox

oc login -u system:admin



魏新宇

  • "大魏分享"运营者、红帽资深解决方案架构师

  • 专注开源云计算、容器及自动化运维在金融行业的推广

  • 拥有MBA、ITIL V3、Cobit5、C-STAR、TOGAF9.1(鉴定级)等管理认证。

  • 拥有红帽RHCE/RHCA、VMware VCP-DCV、VCP-DT、VCP-Network、VCP-Cloud、AIX、HPUX等技术认证。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK