美文网首页Docker容器Ceph
修复一些使用kolla部署ceph中的问题

修复一些使用kolla部署ceph中的问题

作者: wangwDavid | 来源:发表于2019-04-23 09:54 被阅读0次

    本篇介绍一些对kolla ceph的简单修改.

    --limit bug修复

    commit url : https://review.openstack.org/#/c/648576/

    在上篇的部署中我们提到可以使用--limit来限制部署的节点,如果你的mon和osd节点是分开的,你可以用limit特性来对特定节点的服务进行部署. --limit后面既可以跟具体节点名,也可以使用group名切片的方式,例如storage-osd[0:1], 意思是包括storage-osd组中的前两个节点.

    比如我们只想修复node3节点的osd,就可以用--limit属性

    kolla-ansible/tools/kolla-ansible deploy --configdir ceph-test -i ceph-test/multinode-inventory --passwords ceph-test/passwords.yml --tags ceph -e openstack_release=cephRocky-7.0.2.0002 --limit ceph-node3
    

    但是kolla-ansible会报错

    TASK [ceph : Fetching Ceph keyrings] ***************************************************************************************************************************************
    fatal: [ceph-node3]: FAILED! => {"failed": true, "msg": "'delegate_host' is undefined"}
    
    

    出错的任务如下:

    - name: Fetching Ceph keyrings
      command: docker exec ceph_mon fetch_ceph_keys.py
      register: ceph_files_json
      changed_when: (ceph_files_json.stdout | from_json).changed
      failed_when: (ceph_files_json.stdout | from_json).failed
      delegate_to: "{{ delegate_host }}"
      run_once: True
    

    因为delegate_host需要在mon节点读取,而这次部署只有osd节点,所以该值为空,简单的调整如下:

    - name: Fetching Ceph keyrings
      command: docker exec ceph_mon fetch_ceph_keys.py
      register: ceph_files_json
      changed_when: (ceph_files_json.stdout | from_json).changed
      failed_when: (ceph_files_json.stdout | from_json).failed
      delegate_to: "{{ delegate_host if delegate_host is defined else groups['ceph-mon'][0] }}"
      run_once: True
    

    如果delegate_host未定义就去第一个mon节点获取.

    但是这种做法有个问题,当第一个mon节点需要重装的时候, 如果使用--limit ceph-node1, 那么 delegate_host 是已定义但是None的状态,然后groups['ceph-mon'][0]的mon也是无法工作的.

    所以最好是循环检测一下所有mon的状态, 如下:

    ---
    - name: Running ceph mon check
      become: true
      shell: docker exec ceph_mon ceph health --connect-timeout 1
      delegate_to: "{{ item }}"
      register: ceph_mon_check
      changed_when: False
      failed_when: False
      with_items: "{{ groups['ceph-mon'] }}"
      run_once: true
    
    - name: Registering active mon
      set_fact:
        active_mon: "{{ item.1 }}"
      when: item.0.rc is defined and item.0.rc == 0
      run_once: true
      with_together:
        - "{{ ceph_mon_check.results }}"
        - "{{ groups['ceph-mon'] }}"
    

    通过这个active_mon我们可以知道集群有没有运行的mon, 第一个mon节点除了集群初始化的时候生成keyring以外,完全可以把它当成普通的mon一样来部署修复.

    • 修复获取keyrings的任务
    - name: Fetching Ceph keyrings
      command: docker exec ceph_mon fetch_ceph_keys.py
      register: ceph_files_json
      changed_when: (ceph_files_json.stdout | from_json).changed
      failed_when: (ceph_files_json.stdout | from_json).failed
      delegate_to: "{{ active_mon if active_mon is defined else delegate_host }}"
      run_once: True
    

    这样就解决了kolla部署ceph必须包含mon节点的问题, 我们可以用--limit来限制任何要部署的节点.

    • kolla中第一个mon的修复问题

    kolla中, groups['ceph-mon'][0]是个特殊的mon,当检测到该节点并没有对应的卷(ceph_mon_config)之后, 并且其他mon节点也没有对应卷,会启动generate_cluster.yml任务, 重新生成新的keyring和monmap. 所以对于一个部署好的集群, 如果第一个mon有问题, 需要重新安装mon的时候, 是不能直接用kolla加 --limit来修复的, 使用--limit 后kolla部署的第一个mon节点无法加入旧的集群中.

    有了以上的mon检测任务, 这个问题就很好解决了,当有运行的mon的时候, 就不用启动这个任务. 修改如下:

    - include_tasks: generate_cluster.yml
      when:
        - delegate_host == 'None' and inventory_hostname == groups['ceph-mon'][0]
        - active_mon is not defined
    

    这样我们可以直接用kolla来修复mon.

    mon部署问题

    commit url : https://review.openstack.org/#/c/652606/

    kolla的mon服务启动的时候很奇怪, 当我使用3个mon的时候, 有时候会卡住, 有时候不卡, 这个卡就是所有mon一直处在选举的状态,ceph集群无法访问.当尝试4个5个mon的时候会百分百卡住.

    我对比了kolla的mon启动脚本与ceph-deploy的部署日志.

    先看kolla的关于mon初始化的脚本:

    if [[ ! -e "${MON_DIR}/keyring" ]]; then
        KEYRING_TMP="/tmp/ceph.mon.keyring"
    
        # Generate keyring for current monitor
        ceph-authtool --create-keyring "${KEYRING_TMP}" --import-keyring "${KEYRING_ADMIN}"
        ceph-authtool "${KEYRING_TMP}" --import-keyring "${KEYRING_MON}"
        mkdir -p "${MON_DIR}"
        ceph-mon --mkfs -i "${HOSTNAME}" --monmap "${MONMAP}" --keyring "${KEYRING_TMP}"
        rm "${KEYRING_TMP}"
    fi
    

    重点是mkfs这句, 不管任何情况下都是用monmap, 关键是这个monmap也不全,只有第一个节点.

    再看ceph-deploy的部署日志:

    [root@ceph-node1 ceph-deploy]# ceph-deploy mon create-initial
    ...
    [ceph-node1][INFO ] Running command: ceph-mon --cluster ceph --mkfs -i ceph-node1 --keyring /var/lib/ceph/tmp/ceph-ceph-node1.mon.keyring --setuser 167 --setgroup 167
    ...
    [ceph-node2][DEBUG ] create the monitor keyring file
    [ceph-node2][INFO ] Running command: ceph-mon --cluster ceph --mkfs -i ceph-node2 --keyring /var/lib/ceph/tmp/ceph-ceph-node2.mon.keyring --setuser 167 --setgroup 167
    
    ###############分割线,添加mon#############
    
    [root@ceph-node1 ceph-deploy]# ceph-deploy mon add ceph-node3
    ...
    [ceph-node3][INFO ] Running command: ceph-mon --cluster ceph --mkfs -i ceph-node3 --monmap /var/lib/ceph/tmp/ceph.ceph-node3.monmap --keyring /var/lib/ceph/tmp/ceph-ceph-node3.mon.keyring --setuser 167 --setgroup 167
    

    ceph-deploy中,当集群初始化的时候, 所有mon节点都不使用monmap, 只有当新加节点的时候才添加monmap.

    所以修改kolla的初始化mon脚本如下:

    if [[ ! -e "${MON_DIR}/keyring" ]]; then
        KEYRING_TMP="/tmp/ceph.mon.keyring"
    
        # Generate keyring for current monitor
        ceph-authtool --create-keyring "${KEYRING_TMP}" --import-keyring "${KEYRING_ADMIN}"
        ceph-authtool "${KEYRING_TMP}" --import-keyring "${KEYRING_MON}"
        mkdir -p "${MON_DIR}"
    
        mon_stat=$(ceph mon stat --connect-timeout 1 || true)
        mon_check=$(echo $mon_stat | awk '/mons/{print $0}' | wc -l)
        if [[ ${mon_check} -eq 0 ]]; then
            ceph-mon --mkfs -i "${HOSTNAME}" --keyring "${KEYRING_TMP}"
        else
            MONMAP_TMP="/tmp/ceph.${HOSTNAME}.monmap"
            ceph mon getmap -o "${MONMAP_TMP}"
            ceph-mon --mkfs -i "${HOSTNAME}" --monmap "${MONMAP_TMP}" --keyring "${KEYRING_TMP}"
            rm "${MONMAP_TMP}"
        fi
    
        rm "${KEYRING_TMP}"
    fi
    

    首先检查集群的状态,如果命令有内容输出,那么肯定有一半多mon在运行,这个时候就需要获取monmap并使用.反之,就认为是集群初始化,不使用monmap.

    这个修改和上面的修改搭配,基本可以应对mon的问题.

    服务单独指定问题

    commit url : https://review.opendev.org/#/c/648626/

    我们的ceph集群有很多服务,如果只有某一项服务发生了变化,我们只想改动这个服务对应的容器,那么怎么避免其他的服务发生变化就是需要解决的问题.

    这个问题最常见的就是某个osd出现问题了,我们要修复这个osd, 虽然可以用--limit来指定节点,但是如果该节点有其他服务,比如mon/mds/mgr这些,那们如何只让程序对osd进行处理:

    首先我们可以在all.yml中定义一个字典:

    ceph_install_daemons:
      mon-daemon: "yes"
      mgr-daemon: "yes"
      osd-daemon: "yes"
      rgw-daemon: "yes"
      mds-daemon: "yes"
      nfs-daemon: "yes"
    

    注意和enable来区分,enable某个服务是指这个ceph集群中启用了这个服务,而ceph_install_daemons中包含的项是你这次部署具体想改动的项.默认的包含所有服务,如果你只想改动osd,那么在globals.yml修改一下:

    ceph_install_daemons:
      mon-daemon: "no"
      mgr-daemon: "no"
      osd-daemon: "yes"
      rgw-daemon: "no"
      mds-daemon: "no"
      nfs-daemon: "no"
    

    这样我们就达到了只改动osd的目的.

    当然,在kolla-ansible中你要修改一下ceph的deploy.yml:

    ---
    - include_tasks: config.yml
    
    - include_tasks: bootstrap_mons.yml
      when:
        - inventory_hostname in groups['ceph-mon']
        - ceph_install_daemons['mon-daemon'] | bool
    
    - include_tasks: distribute_keyrings.yml
    
    - include_tasks: start_mons.yml
      when:
        - inventory_hostname in groups['ceph-mon']
        - ceph_install_daemons['mon-daemon'] | bool
    
    - include_tasks: start_mgrs.yml
      when:
        - inventory_hostname in groups['ceph-mgr']
        - ceph_install_daemons['mgr-daemon'] | bool
    
    - include_tasks: start_ceph_dashboard.yml
      when:
        - enable_ceph_dashboard | bool
        - inventory_hostname in groups['ceph-mon']
    
    - include_tasks: start_nfss.yml
      when:
        - enable_ceph_nfs | bool
        - inventory_hostname in groups['ceph-nfs']
        - ceph_install_daemons['nfs-daemon'] | bool
    
    - name: configuring client.admin caps
      kolla_ceph_keyring:
        name: client.admin
        caps: "{{ ceph_client_admin_keyring_caps }}"
      run_once: True
      delegate_to: "{{ groups['ceph-mon'][0] }}"
    
    - include_tasks: bootstrap_osds.yml
      when:
        - inventory_hostname in groups['ceph-osd']
        - ceph_install_daemons['osd-daemon'] | bool
    
    - include_tasks: start_osds.yml
      when:
        - inventory_hostname in groups['ceph-osd']
        - ceph_install_daemons['osd-daemon'] | bool
    
    - include_tasks: start_rgws.yml
      when:
        - enable_ceph_rgw | bool
        - inventory_hostname in groups['ceph-rgw']
        - ceph_install_daemons['rgw-daemon'] | bool
    
    - include_tasks: start_rgw_keystone.yml
      when:
        - enable_ceph_rgw_keystone | bool
        - inventory_hostname in groups['ceph-rgw']
        - ceph_install_daemons['rgw-daemon'] | bool
    
    - include_tasks: start_mdss.yml
      when:
        - enable_ceph_mds | bool
        - inventory_hostname in groups['ceph-mds']
        - ceph_install_daemons['mds-daemon'] | bool
    

    upgrade.yml和reconfigure.yml也要做类似的修改.

    有了这个选项, 再加上--limit, 你就可以把改动限制到某个节点上具体的某个服务上,不用担心影响全局的ceph集群.

    crush map change

    commit url : https://review.opendev.org/#/c/647664/

    在kolla中, 当进行osd的bootstrap的时候, 会先将host对应的bucket移动到default下面. 所以, 如果你安装了一个ceph集群, 然后修改了对应的crush map, 比如把host移动到rack下面, 这时问题来了:当集群中的一个osd损坏之后, 如果用kolla重新部署, 那么对应的host又被移动到default下面.

    ceph osd crush add-bucket "${host_bucket_name}" host
    ceph osd crush move "${host_bucket_name}" root=${CEPH_ROOT_NAME:-default}
    # Adding osd to crush map
    ceph osd crush add "${OSD_ID}" "${OSD_INITIAL_WEIGHT}" host="${HOSTNAME}${CEPH_ROOT_NAME:+-${CEPH_ROOT_NAME}}"
    

    解决问题的办法就是, 添加一个判断, 如果osd对应的host已经在crush map中,就不移动host对应的bucket.

        host_bucket_name="${HOSTNAME}${CEPH_ROOT_NAME:+-${CEPH_ROOT_NAME}}"
        host_bucket_check=$(ceph osd tree | awk '/'"${host_bucket_name}"'/{print $0}' | wc -l)
        if [[ "${host_bucket_check}" -eq 0 ]]; then
            ceph osd crush add-bucket "${host_bucket_name}" host
            ceph osd crush move "${host_bucket_name}" root=${CEPH_ROOT_NAME:-default}
        fi
    
        # Adding osd to crush map
        ceph osd crush add "${OSD_ID}" "${OSD_INITIAL_WEIGHT}" host="${HOSTNAME}${CEPH_ROOT_NAME:+-${CEPH_ROOT_NAME}}"
    

    mon和osd使用hostname

    commit url : https://review.opendev.org/654417

    用kolla部署的mon和osd, 名称默认都是IP, 有时候我们想部署成hostname为主的集群,这样在维护的时候可以更直观的知道是哪台节点.

    我的修改中增加了对hostname的支持, 用法很简单, 在globals.yml中定义如下变量即可.

    ceph_mon_host_type: "HOSTNAME"
    ceph_osd_host_type: "HOSTNAME"
    

    NOTE: 不要对已经部署好的集群进行如下操作, 这样会导致旧的集群mon丢失, 因为mon在初始化的时候是以mon对应的节点名称命名的,之前使用IP创建的, 现在改成hostname会造成db丢失. 对osd的影响则是如果修复之前损坏的osd,则会修改之前节点的crush map.

    总结

    通过以上的修复,我们可以做到针对某一个ceph组件具体到某一个节点上的修改.这个粒度其实还不够小, 后面我会讲一下如何避免同一节点上多个osd节点的重启. 毕竟osd是集群里最怕重启的组件.

    相关文章

      网友评论

        本文标题:修复一些使用kolla部署ceph中的问题

        本文链接:https://www.haomeiwen.com/subject/udymgqtx.html