Ubuntu下制作Nginx deb安装包

因为工作需要需要制作deb安装包。
在老大的帮助下,终于搞成功了。
下面来看一下制作方法。我们以制作Nginx的deb安装包为例子。
首先看一下 脚本目录结构:


image.png

build.sh 打包deb脚本
  nginx nginx控制脚本,用来在命令行执行 nginx start stop restar等命令。提取于nginx官方的deb包中。
  post与pre则为打包成deb包后,安装deb包时所需要执行的脚步。
余下则是源码压缩包,都是nginx所需要的依赖。

#!/usr/bin/env bash
##############################
#     编译Nginx二进制安装包     #
##############################

################ 设置一些全局变量 #################

# 用来保存 打包后的 deb文件
WORKDIR="/home/zhai"
test -z $WORKDIR &&
    echo -e "工作目录不存在,即将退出程序" &&
    exit 1

# i386是32位的,amd64是64位
[[ `uname -m` == "x86_64" ]] && ARCH="x86_64" || ARCH="i386"

# 获得linux发行版,版本号,版本名称
LINUX=$(python -c "import platform;dist=platform.dist();print dist[0].lower(), dist[1], dist[2]")
LINUX_VERSION="$(echo $LINUX | cut -d' ' -f1)"
LINUX_VS_NUMBER="$(echo $LINUX | cut -d' ' -f2)"
LINUX_VS_NAME="$(echo $LINUX | cut -d' ' -f3)"

# 获得发行版+版本号 如 ubuntu14
ITERATION="$LINUX_VERSION$(echo $LINUX_VS_NUMBER | cut -d'.' -f1)"
# 版权信息
PACKAGE="nginx"
VERSION="1.12.0"
VENDOR="ZHAI"
URL="http://www.jianshu.com/u/4ffde5305e8f"
LICENSE="GPL"

# 临时文件,保存压缩文件解包后的内容
BUILD_PATH="/tmp/$PACKAGE"
# 程序安装路径
# 这个路径是为了方便后面打包deb,
# 要保证此路径下 只能有一个文件夹,就是你的安装程序。
# 每次打包前,都要清理次目录,保证打包环境的干净。
INSTALL_PATH="/opt/deb"

# 根据发行版选择对应的打包格式
case $LINUX_VERSION in
    ubuntu|debian)
        TARGET="deb"
        ;;
    centos|redhat)
        TARGET="rpm"
        ;;
    *)
        echo "不支持的平台."
        exit 1
esac

################## 开始编译安装 ###################

# 清理旧的解包文件
# 清理打包环境,保证打包前 此路径下文件环境的干净。
rm -rf $BUILD_PATH
rm -rf $INSTALL_PATH
mkdir -p $BUILD_PATH
mkdir -p $INSTALL_PATH

# # ${var} 与 $var 是一个意思 都是引用(使用)一个变量
# # $var 引用$后面第一个变量的值,这个第一个变量指的是 从$开始 一直到遇到第一个空格,非英文字符或者另外一个$为止
# #   当你需要一个动态变量拼接字符的时候 
# #   例如:var 是动态变量,num=$var-path   这时候 引用的是 var-path变量 而不是 var变量。
# # 怎么办呢 ?这时候就该${}出马了
# # ${var} 引用一个变量var ${}的作用范围只能在 {}以内。
# # num=${var}-path 引用的是 变量 var 而不是 var-path 因为${}的作用范围只能在{}以内
SOURCE_DIR=$(pwd)
# 安装依赖 zlib
tar xvf zlib-*.gz -C $BUILD_PATH
cd ${BUILD_PATH}/zlib*
./configure
make
make install
cd $SOURCE_DIR

# 安装依赖 openssl
tar xvf openssl-*.gz -C $BUILD_PATH
cd ${BUILD_PATH}/openssl**
./config
make
make install 
cd $SOURCE_DIR

# 解包pcre源码
# pcre 依赖不需要安装,只需要把源码路径配置到 nginx编译参数中即可
tar xvf pcre-*.gz -C $BUILD_PATH

# 编译安装nginx
# # 配置编译参数
#   prefix nginx安装路径
#   剩下两个参数表示,开启ssl,和pcre功能。
# 暂时只用设置这两个参数,可以根据需求进行添加。
tar xvf ${PACKAGE}-${VERSION}.tar.* -C $BUILD_PATH
cd ${BUILD_PATH}/${PACKAGE}-${VERSION}
PREFIX="nginx"
./auto/configure --prefix=$INSTALL_PATH/$PREFIX \
    --with-http_ssl_module \
    --with-pcre=$BUILD_PATH/pcre*   # 配置prce源码文的路径
make
make install
cd $SOURCE_DIR

#################### 开始打包deb #####################
# FPM常用参数:
# -s:指定源类型
# -t:指定目标类型,即想要制作为什么包
# -n:指定包的名字
# -v:指定包的版本号
# -C:指定打包的相对路径 
# -d:指定依赖于哪些包
# -f:第二次包时目录下如果有同名安装包存在,则覆盖它
# -p:输出的安装包的目录,不想放在当前目录下就需要指定
# --post-install:软件包安装完成之后所要运行的脚本;同--offer-install
# --pre-install:软件包安装之前所要运行的脚本;同--before-install
# --post-uninstall:软件包卸载完成之后所要运行的脚本;同--offer-remove
# --pre-uninstall:软件包卸载之前所要运行的脚本;同—before-remove

# 有几个地方需要说一下
# -C 值的就是 你的程序安装路径 例如 你程序安装在 /opt/deb/nginx
# 那么 -C 路径就是 /opt/deb 而不是 /opt/deb/niginx 切记
# 因为 fpm 会把 -C 路径下的 所有文件夹都打包了。
# 因此 要保证 -C 路径下 只能有一个你的软件目录,而不能有其他的。
# 列如:-C 为 /opt/deb 此时 deb下有三个文件目录 nginx apaceh php 那么 
# fpm 会把这三个文件全部打包在一起。这不是我们想要,我们只想要单独的nginx。
# 所以要保证 nginx下只有一个文件目录。

# fpm打包后的deb,在安装的时候,安装路径为 -C 路径下的 文件目录为顶级安装路径。
# 也就是说 -C只是一个 打包时候所用的 寻找安装程序位置的路径。
# 安装deb时候 将 -C 转换为 /  也就是 根路径去安装 
# 例如 -C /opt/deb
# 软件为 nginx 此时完整路径为 /opt/deb/nginx
# 安装的时候 其实是安装在 /nginx 直接安装在了根路径下,而不是 /opt/deb下。

# 怎么才能安装在 /opt/deb下呢?
# 这时候就需要 --prefix 参数了。
# --prefix 指定安装软件时候的 绝对路径。
# 例如 指定 --prefix 为 /home/wo/deb
# 那么软件就会安装在 /home/wo/deb/nginx 路径下。

# 还有一点
# 软件最终安装好时候的路径 一定要 与 软件编译安装时指定的安装路径一样,不然会有很多的路径错误。
# 这点很重要
# 例如 nginx 编译时候 指定的安装路径为 -prefix=/opt/deb/nginx
# 那么打包成deb 安装的时候 安装路径一定也要是 /opt/deb/nginx
SCRIPTS_PATH=$(pwd)
case $LINUX_VERSION in
    ubuntu|debian)
        fpm -f -s dir \
            -t $TARGET \
            -n $PACKAGE \
            -v $VERSION \
            -C $INSTALL_PATH \
            -p $BUILD_PATH/ \
            --prefix $INSTALL_PATH \
            --iteration $ITERATION \
            --license $LICENSE \
            --vendor $VENDOR \
            --url $URL \
            --deb-no-default-config-files \
            --pre-install $SCRIPTS_PATH/pre-install \
            --post-install $SCRIPTS_PATH/post-install \
            --pre-uninstall $SCRIPTS_PATH/pre-uninstall \
            --post-uninstall $SCRIPTS_PATH/post-uninstall
        ;;
    centos|redhat)
        fpm -f -s dir \
            -t $TARGET \
            -n $PACKAGE \
            -v $VERSION \
            -C $INSTALL_PATH \
            -p $BUILD_PATH/ \
            --prefix $INSTALL_PATH
            --iteration $ITERATION \
            --license $LICENSE \
            --vendor $VENDOR \
            --url $URL \
            --pre-install $SCRIPTS_PATH/pre-install \
            --post-install $SCRIPTS_PATH/post-install \
            --pre-uninstall $SCRIPTS_PATH/pre-uninstall \
            --post-uninstall $SCRIPTS_PATH/post-uninstall
        ;;
    *)
        echo "Unsupport platform."
        exit 1
esac
PACKDIR=${WORKDIR}/packages/LINUX_VERSION/`echo $LINUX_VS_NUMBER| cut -d'.' -f1`/${ARCH}
#cd -
# 移动deb到 工作目录
mkdir -p $PACKDIR
mv ${BUILD_PATH}/${PACKAGE}_${VERSION}-${ITERATION}_*.${TARGET} ${PACKDIR}/${PACKAGE}-${VERSION}.${ARCH}.${TARGET}

pre-install脚本
pre-install 运行期间为 软件安装之前,如果有Nginx旧版本在运行,那么就会结束Nginx旧版本进行,避免deb包的安装失败。

#!/usr/bin/env bash

#############################################
######  软件包安装之前所要运行的脚本   #######
#############################################

# 结束 nginx进程,如果存在的话
retval=$(ps -A | grep nginx | grep -v grep | awk '{print $1}' | wc -l)
if [[ $retval -ne 0 ]]; then
    ps -A | grep nginx | grep -v grep | awk '{print $1}' | xargs kill -9
fi

post-install脚本
post-install 运行期间为 软件安装完成之后,负责一些环境变量的设置。

#!/usr/bin/env bash

#############################################
#####     软件包安装完成后所要运行的脚本     #####
#############################################

LINUX=$(python -c "import platform;dist=platform.dist();print dist[0].lower(), dist[1], dist[2]")
LINUX_VERSION="$(echo $LINUX | cut -d' ' -f1)"
NGINX_PATH="/opt/deb/nginx/nginx"
NGINX_CONF="/opt/deb/nginx/conf/nginx.conf"
# pid 文件路径
PID_PATH="pid        /opt/deb/nginx/logs/nginx.pid;"

# 将pid路径配置到 nginx配置文件中
case $LINUX_VERSION in
    ubuntu|debian)
        LN=$(grep -n "#pid" $NGINX_CONF | cut -d: -f1)
        sed -i "$LN a\\$PID_PATH" $NGINX_CONF
        
        # 删除旧nginx控制脚本,如果有的话,并将新nginx控制脚本移过去
        test -f /etc/init.d/nginx && rm -rf /etc/init.d/nginx
        cp $NGINX_PATH /etc/init.d/nginx
        ;;
    centos|redhat)
        LN=$(grep -n "#pid" $NGINX_CONF | cut -d: -f1)
        sed -i "$LN a\\$PID_PATH" $NGINX_CONF

        rm /etc/init.d/nginx -f
        cp $NGINX_PATH /etc/init.d/nginx
        ;;
    *)
        ;;
esac

pre-uninstall脚本
pre-uninstall脚本运行期间为 程序卸载删除之前,负责结束程序进程解除占用。

#!/usr/bin/env bash

#############################################
######     软件包安装之前所要运行的脚本     ######
#############################################

# 结束 nginx进程,如果存在的话
retval=$(ps -A | grep nginx | grep -v grep | awk '{print $1}' | wc -l)
if [[ $retval -ne 0 ]]; then
    ps -A | grep nginx | grep -v grep | awk '{print $1}' | xargs kill -9
fi

post-uninstall脚本
post-uninstall脚本运行期间为 程序卸载删除完成后,负责清理程序残留文件。

#!/usr/bin/env bash

#############################################
#####     软件包安装完成后所要运行的脚本     #####
#############################################

LINUX=$(python -c "import platform;dist=platform.dist();print dist[0].lower(), dist[1], dist[2]")
LINUX_VERSION="$(echo $LINUX | cut -d' ' -f1)"

INSTALL_PATH="/opt/deb"
NGINXDIR=$INSTALL_PATH/nginx
case $LINUX_VERSION in
    ubuntu|debian)
        test -d $NGINXDIR && rm -rf $NGINXDIR
        ;;
    centos|redhat)
        test -d $NGINXDIR && rm -rf $NGINXDIR
        ;;
    *)
        ;;
esac
test -f /etc/init.d/nginx && rm -rf /etc/init.d/nginx

nginx为控制Nginx启动,停止,重启的脚本。提取与官方deb安装包中(安装官方deb包后,脚本路径为 /etc/init.d/nginx),有几个地方需要改一下就可以使用了。

#!/usr/bin/env bash

### BEGIN INIT INFO
# Provides:   nginx
# Required-Start:    $local_fs $remote_fs $network $syslog $named
# Required-Stop:     $local_fs $remote_fs $network $syslog $named
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts the nginx web server
# Description:       starts nginx using start-stop-daemon
### END INIT INFO
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
################ 此处为修改的部分 ###########################

# nginx 执行文件路径
NGINX_PATH="/opt/deb/nginx/sbin/nginx"
# nginx配置文件路径
NGINX_CONF="/opt/deb/nginx/conf/nginx.conf"
# 开启日志输出
# 开启日志输入,一定不能写在这里,不然会被默认值给覆盖了。
# 一定要写在 最后面 case "$1" in 这一行的上面
# VERBOSE='yes'
#DAEMON=/usr/sbin/nginx
DAEMON=$NGINX_PATH
NAME=nginx
DESC=nginx

# Include nginx defaults if available
if [ -r /etc/default/nginx ]; then
    . /etc/default/nginx
fi

test -x $DAEMON || exit 0

. /lib/init/vars.sh
. /lib/lsb/init-functions

# Try to extract nginx pidfile
PID="/opt/deb/nginx/logs/nginx.pid"
if [ -z "$PID" ]
then
    PID=/run/nginx.pid
fi
#################   修改结束   ###################

# Check if the ULIMIT is set in /etc/default/nginx
# ulimit 用于限制 shell 启动进程所占用的资源
# nginx 默认是没有开启的
if [ -n "$ULIMIT" ]; then
    # Set the ulimits
    ulimit $ULIMIT
fi

#
# Function that starts the daemon/service
#
do_start()
{
    # Return
    #   0 if daemon has been started
    #   1 if daemon was already running
    #   2 if daemon could not be started
    start-stop-daemon --start --quiet --pidfile $PID --exec $DAEMON --test > /dev/null \
        || return 1
    start-stop-daemon --start --quiet --pidfile $PID --exec $DAEMON -- \
        $DAEMON_OPTS 2>/dev/null \
        || return 2
}

test_nginx_config() {
    $DAEMON -t $DAEMON_OPTS >/dev/null 2>&1
}

#
# Function that stops the daemon/service
#
do_stop()
{
    # Return
    #   0 if daemon has been stopped
    #   1 if daemon was already stopped
    #   2 if daemon could not be stopped
    #   other if a failure occurred
    start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PID --name $NAME
    RETVAL="$?"

    sleep 1
    return "$RETVAL"
}

#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
    start-stop-daemon --stop --signal HUP --quiet --pidfile $PID --name $NAME
    return 0
}

#
# Rotate log files
#
do_rotate() {
    start-stop-daemon --stop --signal USR1 --quiet --pidfile $PID --name $NAME
    return 0
}

#
# Online upgrade nginx executable
#
# "Upgrading Executable on the Fly"
# http://nginx.org/en/docs/control.html
#
do_upgrade() {
    # Return
    #   0 if nginx has been successfully upgraded
    #   1 if nginx is not running
    #   2 if the pid files were not created on time
    #   3 if the old master could not be killed
    if start-stop-daemon --stop --signal USR2 --quiet --pidfile $PID --name $NAME; then
        # Wait for both old and new master to write their pid file
        while [ ! -s "${PID}.oldbin" ] || [ ! -s "${PID}" ]; do
            cnt=`expr $cnt + 1`
            if [ $cnt -gt 10 ]; then
                return 2
            fi
            sleep 1
        done
        # Everything is ready, gracefully stop the old master
        if start-stop-daemon --stop --signal QUIT --quiet --pidfile "${PID}.oldbin" --name $NAME; then
            return 0
        else
            return 3
        fi
    else
        return 1
    fi
}
# 开启日志输出
# 这个开启日志的 一定要写在这里,不然会被默认值给覆盖了。
VERBOSE='yes'
case "$1" in
    start)
        [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
        do_start
        case "$?" in
            0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
            2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        esac
        ;;
    stop)
        [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
        do_stop
        case "$?" in
            0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
            2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        esac
        ;;
    restart)
        log_daemon_msg "Restarting $DESC" "$NAME"

        # Check configuration before stopping nginx
        if ! test_nginx_config; then
            log_end_msg 1 # Configuration error
            exit 0
        fi

        do_stop
        case "$?" in
            0|1)
                do_start
                case "$?" in
                    0) log_end_msg 0 ;;
                    1) log_end_msg 1 ;; # Old process is still running
                    *) log_end_msg 1 ;; # Failed to start
                esac
                ;;
            *)
                # Failed to stop
                log_end_msg 1
                ;;
        esac
        ;;
    reload|force-reload)
        log_daemon_msg "Reloading $DESC configuration" "$NAME"

        # Check configuration before reload nginx
        #
        # This is not entirely correct since the on-disk nginx binary
        # may differ from the in-memory one, but that's not common.
        # We prefer to check the configuration and return an error
        # to the administrator.
        if ! test_nginx_config; then
            log_end_msg 1 # Configuration error
            exit 0
        fi

        do_reload
        log_end_msg $?
        ;;
    configtest|testconfig)
        log_daemon_msg "Testing $DESC configuration"
        test_nginx_config
        log_end_msg $?
        ;;
    status)
        status_of_proc -p $PID "$DAEMON" "$NAME" && exit 0 || exit $?
        ;;
    upgrade)
        log_daemon_msg "Upgrading binary" "$NAME"
        do_upgrade
        log_end_msg 0
        ;;
    rotate)
        log_daemon_msg "Re-opening $DESC log files" "$NAME"
        do_rotate
        log_end_msg $?
        ;;
    *)
        echo "Usage: $NAME {start|stop|restart|reload|force-reload|status|configtest|rotate|upgrade}" >&2
        exit 3
        ;;
esac

:

打包后的deb 就保存在我们设置的工作目录中。


image.png

在看一下 deb的信息 :


image.png

我们看到确实安装在 /opt/deb/nginx路径之下
我们安装一下
image.png

image.png

安装成功 ,没毛病。运行一下,试一试控制命令:


image.png

ok 很完美!
image.png

ok 好了 完美运行

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

推荐阅读更多精彩内容