Ceph 编译以及构建rpm包

概述

 对于一个ceph开发人员来说编译源码以及打rpm是其必备技能。无论是fix bug还是向社区提交pull request都离不开编译源码。而rpm包又是linux系统发行产品时常用的格式。在官网和其他blog可以很多这方面的介绍,我在这里把自己编译的步奏,以及遇到的坑及解决办法记录一下,仅供新人参考。

编译源码

环境介绍:
  • ceph version: Luminous 12.2.10
  • 硬件环境:Centos7虚拟机/Centos7 docker container
准备工作
  • 安装yum源
    这些源用于安装常用工具,执行install-reps.sh安装以来包使用,列表如下:
-rw-r--r--. 1 root root 2523 Jan  8 07:10 CentOS-Base.repo
-rw-r--r--. 1 root root 1309 Jan  8 08:22 CentOS-CR.repo
-rw-r--r--. 1 root root  649 Nov 23 13:16 CentOS-Debuginfo.repo
-rw-r--r--. 1 root root  314 Nov 23 13:16 CentOS-fasttrack.repo
-rw-r--r--. 1 root root  630 Nov 23 13:16 CentOS-Media.repo
-rw-r--r--. 1 root root  916 Jan  8 07:10 CentOS-SCLo-scl.repo
-rw-r--r--. 1 root root  898 Jan  8 07:10 CentOS-SCLo-scl-rh.repo
-rw-r--r--. 1 root root 1331 Nov 23 13:16 CentOS-Sources.repo
-rw-r--r--. 1 root root 5701 Nov 23 13:16 CentOS-Vault.repo
-rw-r--r--. 1 root root  664 Jan  8 07:10 epel.repo
-rw-r--r--. 1 root root  951 Oct  2  2017 epel.repo.rpmnew
-rw-r--r--. 1 root root 1050 Oct  2  2017 epel-testing.repo
-rw-r--r--. 1 root root  155 Jan  8 07:10 mirrors.aliyun.com_epel_7_x86_64_.repo
-rw-r--r--. 1 root root  153 Jan  8 07:10 mirrors.aliyun.com_epel_x86_64_.repo
  • 安装git
yum install git

You have enabled checking of packages via GPG keys. This is a good thing.
However, you do not have any GPG public keys installed. You need to download
the keys for packages you wish to install and install them.
You can do that by running the command:
    rpm --import public.gpg.key

从别的机器拷贝/etc/ceph/rpm-gpg 过来,然后执行
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

  • 下载12.2.10源码
    git clone -b v12.2.10 --single-branch git://github.com/ceph/ceph.git master

  • 更新子模块代码
    git submodule update —init —recursive

下面两步如果环境已经有了切版本合适就可以跳过

  • 安装gcc
git clone [https://github.com/gcc-mirror/gcc.git](https://github.com/gcc-mirror/gcc.git)

b.mkdir build ; cd build
../configure --prefix=/usr --disable-multilib 
c.yum install -y gmp-devel libmpc-devel mpfr-devel flex
d.make -j16 > log 2>&1 && make install >log 2>&1 &
  • 升级cmake
wget https://cmake.org/files/v3.9/cmake-3.9.2.tar.gz
//解压后自行安装
编译
  • 执行install-deps.sh来安装编译时需要的各种依赖包
    sh install-deps.sh

Note:
1.这一步一般要耗费较长时间,所以我们可以执行这一步的时候打开yum的缓存模式,把依赖包缓存在本地,随后把这些rpm包建立一个自己的yum源,这样下次安装的时候就从本地的yum源安装,会大大缩减时间!

[root@xt-53 ceph-12.2.10]# cat /etc/yum.conf
[main]
cachedir=/var/cache/yum/$basearch/$releasever
keepcache=1  //置为1,打开缓存模式
debuglevel=2
...

缓存的包会保留在/var/cache/yum/x86_64/7/ 下面
2.如果是容器内编译也可以把安装完依赖包的容器提交到新的镜像,之后用这个镜像启动的容器就不用再安装依赖包了。
3.install-deps.sh带的默认的yum源比较慢,可以更改更快的yum源
install-deps.sh中

$SUDO yum-config-manager --add-repo https://dl.fedoraproject.org/pub/epel/$VERSION_ID/x86_64/
更改为
$SUDO yum-config-manager --add-repo https://mirrors.aliyun.com/epel/$VERSION_ID/x86_64/
  • 执行do_cmake.sh
    sh do_cmake.sh

  • 开始make
    make -j16 > log 2>&1 & //线程数等于cpu core的2倍,可以提高编译的速度
    当然我们也可以只编译某一个模块,比如只编译client就可以
    make client > log 2>&1 &

最小测试用例

 当我们更改了代码准备提交到公司内部repo或者社区repo都需要先执行一下最小测试集,看看自己修改的代码有没有影响到别的模块(社区也会进行同样的测试)。

  • ctest
    可以单独跑一个测试用例,若不加参数就跑所有的测试,和make一样,可以用-j选项来多线程同时跑。
    例如:
# ctest -R cephfs
Test project /home/ivan/ws/Luminous/code/ceph-12.2.10/build
    Start 42: unittest_libcephfs_config
1/1 Test #42: unittest_libcephfs_config ........   Passed    0.02 sec

100% tests passed, 0 tests failed out of 1

Total Test time (real) =   0.06 sec

 也可以用-V选项来使运行过程打印到前台

# ctest -V -R client
UpdateCTestConfiguration  from :/home/ivan/ws/Luminous/code/ceph-12.2.10/build/DartConfiguration.tcl
UpdateCTestConfiguration  from :/home/ivan/ws/Luminous/code/ceph-12.2.10/build/DartConfiguration.tcl
Test project /home/ivan/ws/Luminous/code/ceph-12.2.10/build
Constructing a list of tests
Done constructing a list of tests
Checking test dependency graph...
Checking test dependency graph end
test 138
    Start 138: unittest_mclock_client_queue

138: Test command: /home/ivan/ws/Luminous/code/ceph-12.2.10/build/bin/unittest_mclock_client_queue
138: Test timeout computed to be: 3600
138: [==========] Running 4 tests from 1 test case.
138: [----------] Global test environment set-up.
138: [----------] 4 tests from MClockClientQueueTest
138: [ RUN      ] MClockClientQueueTest.TestSize
138: [       OK ] MClockClientQueueTest.TestSize (0 ms)
138: [ RUN      ] MClockClientQueueTest.TestEnqueue
138: [       OK ] MClockClientQueueTest.TestEnqueue (0 ms)
138: [ RUN      ] MClockClientQueueTest.TestEnqueueStrict
138: [       OK ] MClockClientQueueTest.TestEnqueueStrict (0 ms)
138: [ RUN      ] MClockClientQueueTest.TestRemoveByClass
138: [       OK ] MClockClientQueueTest.TestRemoveByClass (0 ms)
138: [----------] 4 tests from MClockClientQueueTest (1 ms total)
138:
138: [----------] Global test environment tear-down
138: [==========] 4 tests from 1 test case ran. (1 ms total)
138: [  PASSED  ] 4 tests.
1/1 Test #138: unittest_mclock_client_queue .....   Passed    0.04 sec

The following tests passed:
    unittest_mclock_client_queue

100% tests passed, 0 tests failed out of 1

Total Test time (real) =   0.08 sec
  • make check
    编译以及顺便跑所有的测试用例,可以加-j选项来启动多线程。

构建RPM包

 当我们需要发布产品时就需要把各个模块打成rpm包。我把官网上面的环节再加上自己的特殊需求写了个脚本来实现一键打包功能。
 我们首先需要更改make-disk,该脚本主要用于生成ceph.spec和ceph-*.tar.bz2文件以供后面打rpm包使用。我们主要改变了rpm_version,rpm_release ,是否下载boost库等.

# cat make-dist
#!/bin/sh -e

DOWNLOAD_BOOST=$1

if [ ! -d .git ]; then
    echo "no .git present.  run this from the base dir of the git checkout."
    exit 1
fi

##############################################################
#
# Version is very import, we add a Version.txt to record it 
# There should use own Version.txt instead git tag
#
##############################################################
version=`cat Version.txt | grep VERSION |awk -F '=' '{print $2}'`

[ -z "$version" ] && version=`git describe --match 'v*' | sed 's/^v//'`
outfile="ceph-$version"

echo "version $version"

# update submodules
echo "updating submodules..."
force=$(if git submodule usage 2>&1 | grep --quiet 'update.*--force'; then echo --force ; fi)
if ! git submodule sync || ! git submodule update $force --init --recursive; then
    echo "Error: could not initialize submodule projects"
    echo "  Network connectivity might be required."
    exit 1
fi

download_boost() {
    boost_version=$1
    shift
    boost_md5=$1
    shift
    boost_version_underscore=$(echo $boost_version | sed 's/\./_/g')
    boost_fname=boost_${boost_version_underscore}.tar.bz2
    set +e
    if [ "${DOWNLOAD_BOOST}" == "yes" ];then
        while true; do
            url_base=$1
            shift
            if [ -z $url_base ]; then
                echo "Error: failed to download boost."
                exit
            fi
            url=$url_base/$boost_fname

            wget -c --no-verbose -O $boost_fname $url
            if [ $? != 0 -o ! -e $boost_fname ]; then
                echo "Download of $url failed"
            elif [ $(md5sum $boost_fname | awk '{print $1}') != $boost_md5 ]; then
                echo "Error: failed to download boost: MD5 mismatch."
            else
                break
            fi
        done
    fi
    set -e
    tar xjf $boost_fname -C src \
        --exclude="$boost_version_underscore/libs/*/doc" \
        --exclude="$boost_version_underscore/libs/*/example" \
        --exclude="$boost_version_underscore/libs/*/examples" \
        --exclude="$boost_version_underscore/libs/*/meta" \
        --exclude="$boost_version_underscore/libs/*/test" \
        --exclude="$boost_version_underscore/tools/boostbook" \
        --exclude="$boost_version_underscore/tools/quickbook" \
        --exclude="$boost_version_underscore/tools/auto_index" \
        --exclude='doc' --exclude='more' --exclude='status'
    mv src/boost_${boost_version_underscore} src/boost
    tar cf ${outfile}.boost.tar ${outfile}/src/boost
    rm -rf src/boost
}

# clean out old cruft...
echo "cleanup..."
rm -f $outfile*

# build new tarball
echo "building tarball..."
bin/git-archive-all.sh --prefix ceph-$version/ \
               --verbose \
               --ignore corpus \
               $outfile.tar

# populate files with version strings
echo "including src/.git_version, ceph.spec"

# The command finds the most recent tag that is reachable from a commit. If the tag points to the commit, 
# then only the tag is shown. Otherwise, it suffixes the tag name with the number of additional commits on
# top of the tagged object and the abbreviated object name of the most recent commit. The result is a 
# human-readable" object name which can also be used to identify the commit to other git commands.
(git rev-parse HEAD ; git describe) 2> /dev/null > src/.git_version

# if the version has '-' in it, it has a 'release' part,
# like vX.Y.Z-N-g<shortsha1>.  If it doesn't, it's just
# vX.Y.Z.  Handle both, and translate - to . for rpm
# naming rules (the - separates version and release).

if expr index $version '-' > /dev/null; then
    rpm_version=`echo $version | cut -d - -f 1-1`
    rpm_release=`echo $version | cut -d - -f 2- | sed 's/-/./'`
else
    rpm_version=$version
        # rpm style: ceph-"module"-"version"-"commit_id"
        # example: ceph-mds-12.2.10.mh.0-1.ga200519.el7.x86_64.rpm
    rpm_release=`tail -n 1 src/.git_version | cut -d - -f 2- | sed 's/-/./'`
fi

for spec in ceph.spec.in alpine/APKBUILD.in; do
    cat $spec |
        sed "s/@VERSION@/$rpm_version/g" |
        sed "s/@RPM_RELEASE@/$rpm_release/g" |
        sed "s/@TARBALL_BASENAME@/ceph-$version/g" > `echo $spec | sed 's/.in$//'`
done
ln -s . $outfile
tar cvf $outfile.version.tar $outfile/src/.git_version $outfile/ceph.spec $outfile/alpine/APKBUILD
# NOTE: If you change this version number make sure the package is available
# at the three URLs referenced below (may involve uploading to download.ceph.com)
boost_version=1.66.0
    download_boost $boost_version b2dfbd6c717be4a7bb2d88018eaccf75 \
    https://dl.bintray.com/boostorg/release/$boost_version/source \
    https://downloads.sourceforge.net/project/boost/boost/$boost_version \
    https://download.ceph.com/qa
tar --concatenate -f $outfile.all.tar $outfile.version.tar
tar --concatenate -f $outfile.all.tar $outfile.boost.tar
tar --concatenate -f $outfile.all.tar $outfile.tar
mv $outfile.all.tar $outfile.tar
rm $outfile
rm -f $outfile.version.tar
rm -f $outfile.boost.tar

echo "compressing..."
bzip2 -9 $outfile.tar

echo "done."

脚本make-rpm.sh如下:

# cat make-rpm.sh
#!/bin/bash

#echo $@

#######################################################
#
# build Ceph rpm packages
#
# ./make-rpm.sh
#
########################################################

CLEANBUILD="yes"
INSTALL_DEPS="false"
COMMAND=$1
DOWNLOAD_BOOST="false"

# current dir of this script
BASEDIR=`cd $(dirname $0); pwd -P`

function usage()
{
cat <<EOF

Usage: ./$0 <build|clean> [Flags]

Build ceph and generate rpm packages.

Flags:
    -i,--install-deps      //don't excute install-deps.sh
    -n,--no-cleanbuild     //don't clean build
    --download_boost       // download boost library

    -h,--help              //list help info
EOF
}

function build_rpms()
{
    # we don't need install deps every time
    if [  "$INSTALL_DEPS" == "yes" ];then
        echo "sh ./install-deps.sh"
        #sh ./install-deps.sh
    fi

    if [ "$MODULE" != "" ];then
        echo "compile $MODULE"
    else
        echo "compile all modules"
    fi
    # we only need download boot at first time
    if [ "$DOWNLOAD_BOOST" == "yes" ];then
        echo "make-dist yes"
        ./make-dist yes
    else
        echo "make-dist false"
        ./make-dist false
    fi
    ###########################################
    #
    # Version is very import, we add a Version.txt to record it 
    #
    ###########################################
    version=`cat Version.txt | grep VERSION |awk -F '=' '{print $2}'`

    rm -rf ${BASEDIR}/rpmbuild
    mkdir ${BASEDIR}/rpmbuild && cd ${BASEDIR}/rpmbuild && mkdir BUILD  BUILDROOT  RPMS  SOURCES  SPECS  SRPMS
    cp ${BASEDIR}/ceph-${version}.tar.bz2 ${BASEDIR}/rpmbuild/SOURCES
    tar --strip-components=1 -C ${BASEDIR}/rpmbuild/SPECS/ --no-anchored -xvjf ${BASEDIR}/rpmbuild/SOURCES/ceph-${version}.tar.bz2 "ceph.spec"

    if [ "$CLEANBUILD" == "yes" ];then
        #rpmbuild --define="_topdir "${BASEDIR}"" -ba ${BASEDIR}/rpmbuild/SPECS/ceph.spec --with clean_build
        rpmbuild --define="_topdir "${BASEDIR}"/rpmbuild" -ba ./SPECS/ceph.spec --with clean_build
    else
        #rpmbuild --define '_topdir ./rpmbuild' -ba ${BASEDIR}/rpmbuild/SPECS/ceph.spec
        rpmbuild --define="_topdir "${BASEDIR}"/rpmbuild" -ba ./SPECS/ceph.spec
    fi

    mv ${BASEDIR}/rpmbuild/RPMS/*/* ${BASEDIR}/rpmbuild/
    mv ${BASEDIR}rpmbuild/SRPMS/* ${BASEDIR}/rpmbuild/
}

function make_clean()
{
    echo "clean last build result ..."
    rm -rf rpmbuild
}

function do_work()
{
   if [ "$COMMAND" == "build" ];then
       echo "start building ..."
       build_rpms
   else
       echo "start cleaning"
       make_clean

   fi

}
ARGS=`getopt -o inmc --long install-deps,no-cleanbuild,module:,download_boost,clean -n 'example.sh' -- "$@"`
eval set -- "${ARGS}"

while true
do
    case "$1" in
        -i|--install-deps)
            INSTALL_DEPS="yes"
            echo INSTALL_DEPS $INSTALL_DEPS
            shift
            ;;
        -n|--no-cleanbuild)
            CLEANBUILD="false";
            echo CLEANBULD: $CLEANBUILD;
            shift
            ;;
        --download_boost)
            DOWNLOAD_BOOST="yes";
            echo DOWNLOAD_BOOST $DOWNLOAD_BOOST;
            shift
            ;;
        -c|--clean)
            COMMAND="clean";
            echo COMMAND: $COMMAND;
            shift
            ;;
        --)
            shift;
            break;;
        *) echo "Internal error!;"; exit 1 ;;
    esac
done

if [ $# -lt 1 ];then
    usage
    exit -1
fi

do_work
  • 脚本使用方法
# sh make-rpm.sh -h
Usage: ./make-rpm.sh <build|clean> [Flags]

Build ceph and generate rpm packages.

Flags:
    -i,--install-deps      //don't excute install-deps.sh
    -n,--no-cleanbuild     //don't clean build
    --download_boost       // download boost library

    -h,--help              //list help info

End.
  • build rpm 包
// 开始打包,不安装依赖包,且不下载boost库
sh make-rpm.sh build
  • 清除掉上次编译的残留文件
sh make-rpm.sh clean
或者
sh make-rpm.sh -c
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容