脚本打包方式

由于Nginx实际迁移场景中,部分配置文件、静态文件等存放在Nginx安装路径外,为方便打包源成分,我们提供了一个打包脚本示例。脚本会将Nginx安装路径外源成分按照其原目录结构打包在“/打包路径/Nginx安装路径/sbin/source_related”目录下。

  • 该脚本只是一个打包示例,不存在危险操作、源码泄露。
  • 仅支持源码编译的Nginx,且二进制在“Nginx安装路径/sbin”目录下。
  • 手动添加迁移场景不支持通过RPM包安装的Nginx迁移。如需迁移,请使用虚拟机镜像迁移场景或手动进行迁移。
  1. 请在源虚拟机的任意位置创建一个.sh脚本文件(例如pack_nginx_sources.sh),脚本内容详见pack_nginx_sources.sh链接。
  2. 执行该脚本以完成打包过程。打包后的tar包位于“/home”目录下。

    1
    bash /path/to/pack_nginx_sources.sh /usr/local/nginx
    

    显示如下内容,则表示打包成功。

    Copying /usr/local/nginx to /home/nginx_mig_tmp ...
     Getting installation configure command paths...
    configure arguments: --prefix=/usr/local/nginx --with-http_ssl_module --with-http_gzip_static_module --with-http_stub_status_module
     Getting startup config file...
    root      2864 32744  0 01:49 pts/1    00:00:00 bash pack_nginx_sources.sh /usr/local/nginx
    root      2881  2864  0 01:49 pts/1    00:00:00 grep nginx
     Scanning included sources in config file...
    [conf file]: /home/nginx_mig_tmp/nginx/conf/fastcgi.conf
    [conf file]: /home/nginx_mig_tmp/nginx/conf/nginx.conf
     Packing tar...
    Nginx related components are packaged into nginx_migration.tar.
    Note: Please manually check and remove unrelated files/dirs if needed.
    Please manually upload it to the node server and extract it using the command: tar xvf nginx_migration.tar -C /custom_path
    • /path/to:脚本实际存放路径。
    • /usr/local/nginx:源Nginx安装目录的绝对路径,请根据实际路径进行修改。
    • 若Nginx指定配置文件启动(即指定-c选项),且安装路径下不存在二进制文件,则需要根据提示信息手动输入Nginx二进制路径,用于打包与二进制相关的配置文件。
    若在Windows系统创建脚本,由于Windows和Linux的换行符表示方式不同,则在Linux系统执行脚本可能会出现以下报错,请按照如下步骤进行操作。
    -bash: ./autoBuild.sh: /bin/bash^M: bad interpreter: No such file or directory
    1. 安装dos2unix。
      1
      yum install dos2unix
      
    2. 安装成功后执行以下命令。
      1
      dos2unix pack_nginx_sources.sh
      
    3. 执行完成后请重新启动脚本。
    若您无可用Yum源安装失败,请执行以下命令,执行完成后请重新启动脚本。
    sed -i 's/\r//g' pack_nginx_sources.sh

  3. 打包完成后请手动删除生成的“/home/nginx_mig_tmp”目录。
  4. 可通过以下两种方式获取源成分。

    • 若使用“源成分包上传”方式,返回“添加成分信息”页签,单击“源成分包上传”“上传”按钮,上传打包的源成分包。
    • 若使用“节点服务器获取”方式,请执行如下命令解压源成分压缩包。
      1. 使用SSH远程登录工具,将压缩包上传至“所属节点”的自定义路径。
      2. 进入保存压缩包文件的自定义目录。
        1
        cd 自定义路径
        
      3. 解压源成分压缩包。
        1
        tar xvf nginx_migration.tar
        
      4. 解压完成,可选择执行如下命令删除源成分压缩包。
        1
        rm -f nginx_migration.tar
        
      5. 指定解压后的文件路径为“源成分所在路径”

pack_nginx_sources.sh

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#!/bin/bash

# 检查命令行参数,确保提供了源Nginx安装目录的绝对路径
if [ $# -ne 1 ]; then
     echo "Usage: $0 <source_nginx_install_dir>"
     exit 1
fi

source_nginx_dir="$1"
source_nginx_binary="$source_nginx_dir/sbin/nginx"
temp_dir="/home/nginx_mig_tmp"
source_nginx_tmp="$temp_dir/$(basename "$source_nginx_dir")"
migration_tar="nginx_migration.tar"

if [ ! -d "$source_nginx_dir" ]; then
     echo "The parameter entered is not a valid directory."
     echo "Usage: $0 <source_nginx_install_dir>"
     exit 1
fi

if [ ! -d "$source_nginx_dir/sbin" ]; then
    echo "The source Nginx installation path does not contain the sbin directory."
    echo "Usage: $0 <source_nginx_install_dir>"
    echo "Notice: This script only supports the source Nginx binary stored in \"<source_nginx_install_dir>/sbin\"."
    exit 1
fi

if [ ! -f "$source_nginx_binary" ]; then
    echo "The source Nginx binary file is not in $source_nginx_dir/sbin."
    echo "Usage: $0 <source_nginx_install_dir>"
    echo "Notice: This script only supports the source Nginx binary stored in \"<source_nginx_install_dir>/sbin\"."
    exit 1
fi

# 步骤一:创建临时目录并复制Nginx安装目录
target_nginx_dir="$(dirname "$source_nginx_tmp")"
mkdir -p "$target_nginx_dir"
echo "Copying $source_nginx_dir to $target_nginx_dir ..."
if ! cp -rp "$source_nginx_dir" "$target_nginx_dir"; then
     echo "Failed to copy the Nginx installation directory"
     exit 1
fi
# 创建指定目录打包包外的成分
source_related_dir="$source_nginx_tmp/sbin/source_related"
mkdir -p "$source_related_dir"
mkdir -p "$source_related_dir/external_confs"
external_confs_record="$source_related_dir/external_confs/external_conf_record.txt"
touch "${external_confs_record}"
chmod 600 "${external_confs_record}"

# 步骤二:获取编译选项指定的依赖文件并复制
echo -e "\e[1;32m Getting installation configure command paths...\e[0m"
keywords="sbin-path|conf-path|error-log-path|http-log-path|http-client-body-temp-path|http-fastcgi-temp-path|http-proxy-temp-path|http-scgi-temp-path|http-uwsgi-temp-path|pid-path|lock-path"
cd "$source_nginx_dir"
strings "$source_nginx_binary" | grep "configure arguments"
strings "$source_nginx_binary" | grep "configure arguments" | grep -Eo "($keywords)=[^[:space:]]+" | awk -F '=' '{print $2}' | while read -r path; do
     # 如果依赖文件已在包内,则跳过复制步骤
     if [[ "$path" == "$source_nginx_dir"* ]]; then
         echo "Skip copying $path because it is in the source Nginx directory."
         continue
     fi

     source_path="$path"

     # 获取相对路径的真实路径
     if [[ "$path" == ../* ]]; then
         source_path=$(realpath --relative-base="$source_nginx_dir" -m "$path")
     fi

     # 如果是nginx的conf和log文件,拷贝所在目录
     if [[ "$source_path" =~ \.conf$ ]] || [[ "$source_path" =~ \.log$ ]]; then
         source_path=$(dirname "$source_path")
     fi

     target_dir="$source_related_dir/$(dirname "$source_path")"
     if [ ! -d "$target_dir" ]; then
         mkdir -p "$target_dir"
     fi
     echo "Copying $source_path to $target_dir ..."
     if ! cp -rp "$source_path" "$target_dir"; then
         echo "Failed to copy file/directory: $source_path"
     fi
 done

# 步骤三:获取启动配置文件并复制
echo " "
echo -e "\e[1;32m Getting startup config file...\e[0m"
ps -ef | grep nginx
nginx_process_info=$(ps -ef | grep nginx)
if grep -q " -c " <<< "$nginx_process_info" || [ -f "$source_nginx_binary" ]; then
    keywords=""
else
  echo -e "\e[1;93m Please refer to the process information of 'ps -ef | grep nginx' above, check whether the source nginx to be migrated is started with a specified configuration file. \e[0m"
  echo -e "\e[1;93m e.g., nginx: master process {path to the nginx binary to be migrated} -c {configuration file path} \e[0m"
  echo -e "\e[1;93m If it is not started based on the specified configuration file, press Enter to skip this step. Otherwise, enter the Nginx binary file path. \e[0m"
  echo "Enter Nginx binary path: "
  read -r nginx_binary_path
  keywords="$nginx_binary_path"
fi
ps -ef | grep nginx | grep -oE "nginx: master process $keywords \-c ([^ ]+)" | while read -r line; do
     CONF_FILE=$(echo "$line" | grep -oE 'c ([^ ]+)' | cut -d ' ' -f2)
     echo "[Startup config file]: $CONF_FILE"
     if [ ! -f "$CONF_FILE" ]; then
         continue
     fi
     conf_dir=$(dirname "$CONF_FILE")
     # 包内的跳过
     if [[ "$conf_dir" == "$source_nginx_dir"* ]]; then
         continue
     fi

     echo "$CONF_FILE" >> "$external_confs_record"

     target_dir=$(dirname "$source_related_dir$conf_dir")
     if [ ! -d "$target_dir" ]; then
         mkdir -p "$target_dir"
     fi
     echo "Copying $conf_dir to $target_dir ..."
     if ! cp -rp "$conf_dir" "$target_dir"; then
         echo "Failed to copy confs dir: $conf_dir"
     fi
 done

# 步骤四:扫描配置文件中引用的外部文件/目录并复制
echo " "
echo -e "\e[1;32m Scanning included sources in config file...\e[0m"
conf_file_list=()
while IFS= read -r -d '' file; do
     conf_file_list+=("$file")
done < <(find "$source_nginx_tmp" -type f -name "*.conf" -print0)

# 入参:[line][relative_base_path]
function handle_included() {
     line="$1"
     relative_base_path="$2"
     path=$(echo "$line" | awk '{print $2}' | sed 's/[";]//g')

     if [[ "$path" == /* ]]; then
         source_path="$path"
         target_path="$source_related_dir$source_path"
     elif [[ "$path" == ../* ]]; then
         source_path=$(realpath --relative-base="$relative_base_path" -m "$path")
         target_path="$source_related_dir$source_path"
     else
         return
     fi

     if [[ "${path##*/}" == \** ]]; then
         source_path=$(dirname "$source_path")
         target_path=$(dirname "$target_path")
     fi

     target_dir=$(dirname "$target_path")
     mkdir -p "$target_dir"
     echo "Copying $source_path to $target_dir ..."
     if ! cp -rp "$source_path" "$target_dir"; then
         echo "Failed to copy file/directory: $path"
     fi
}

for file in "${conf_file_list[@]}"; do
     echo "[conf file]: $file"
     file_dir=$(dirname "$file")
     if [ ! -f "$file" ]; then
         continue
     fi
     # 获取源conf的dir
     if echo "$file" | grep -q "source_related"; then
         source_conf_dir=$(echo "$file_dir" | awk -F 'source_related' '{print $2}')
     else
         source_conf_dir="$source_nginx_dir/conf"
     fi
     # 相对于conf路径
     keywords="include|ssl_certificate|ssl_certificate_key|ssl_dhparam"
     cd "$source_conf_dir"
     grep -wE "^[[:space:]]*($keywords)" "$file" | while read -r line; do
         handle_included "$line" "$source_conf_dir"
     done
     # 相对安装路径
     keywords="error_log|access_log|root|alias|client_body_temp_path|fastcgi_temp_path|proxy_temp_path|proxy_cache_path|scgi_temp_path|uwsgi_temp_path"
     cd "$source_nginx_dir"
     grep -wE "^[[:space:]]*($keywords)" "$file" | while read -r line; do
         handle_included "$line" "$source_nginx_dir"
     done
 done

# 步骤五:清理source_related内,步骤三扫描配置文件时,二次拷贝的源Nginx安装目录
echo " "
cd "$(dirname "$temp_dir")"
source_related_nginx="$source_related_dir$source_nginx_dir"
if [ -d "$source_related_nginx" ]; then
     echo "[remove]: $source_related_nginx"
     rm -rf "${source_related_nginx}"
fi

# 步骤六:打包源成分目录
echo " "
echo -e "\e[1;32m Packing tar...\e[0m"
tar cvf "$migration_tar" "$(basename "$temp_dir")" >/dev/null
if [[ "$?" -ne "${SUCCESS}" ]]; then
     echo "Failed to create tar."
     exit 1
fi

echo "Nginx related components are packaged into $migration_tar."
echo "Note: Please manually check and remove unrelated files/dirs if needed."
echo "Please manually upload it to the node server and extract it using the command: tar xvf $migration_tar -C /custom_path"