项目部署
服务器需要先安装docker、docker-compose,并启动mysql、redis、nginx服务。
准备工作,需要先添加公钥到服务器的authorized_keys文件中,才能进行免密登录。如果登录失败,检测/Users/你的账号/.ssh/known_hosts中是否存在服务器的记录,如果存在,删除即可。
需要在服务器数据目录创建项目名称的目录,如:/data/域名
1.创建项目配置文件
make object
```
根据提示输入域名、admin api端口号、app api的端口号。输入后,会在config目录下生成项目的配置文件。可以调整当中的内容。项目配置文件存在时,不会再次生成。
项目配置文件列表如下:
```
域名
├── docker.admin.yaml # admin api的配置文件
├── docker.app.yaml # app api的配置文件
├── docker-compose.yaml # docker compose配置文件
├── cert # 存放证书,需要手动复制到该目录
└── nginx.conf # nginx配置文件
```
### 2.编译可执行文件
与 #创建项目配置文件 不分先后,执行编译后,会在deploy目录下生成可执行文件与ui静态文件。
```
make install
```
执行后的目录结构如下:
```
deploy
├──api
├────adm
├────app
├──ui
├────admui
├────pcui
└────wx
```
注:
- 单独编译api可执行文件,需要安装go环境,执行`make api`即可。
- 单独编译UI,需要安装nodejs,执行`make ui`即可(nodejs 18版本)。
### 3.打包上传
该阶段会将项目配置文件、可执行文件、ui静态文件打包上传到服务器。需要提前配置好服务器的ssh免密登录。
```
./update.sh <domain>
```
#### 3.1 打包上传时需要修改文件
```
./update.sh <domain> stop
```
stop 期间,还没有进行zip打包,可以修改文件。修改完成后,执行任意键进行文件打包与上传。
#### 3.2 版本回退
```
./update.sh <domain> rollback <version>
```
version为版本号,可以查看packages目录下的版本号,选择回退的版本号。
#### 3.3 只打包不上传
```
./update.sh <domain> pre
```
该命令会在packages目录下生成版本号目录,但是不会上传到服务器。
## 常见问题
### 1.在编译pcui时报错
```
...
Error: error:0308010C:digital envelope routines::unsupported
at new Hash (node:internal/crypto/hash:71:19)
at Object.createHash (node:crypto:133:10)
...
```
出现这个问题,是因为nodejs版本过低,或者过高,目前测试nodejs16版本可以。在项目的package.json中。我添加如下内容:
```
"scripts": {
"serve": "export NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve --mode development",
"build": "export NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build --mode production",
"lint": "vue-cli-service lint"
},
```
注意,我测试时在linux下,nodejs18版本时,通过export命令设置NODE_OPTIONS,可以解决问题。但是在nodejs16版本下,不需要设置NODE_OPTIONS,直接执行vue-cli-service命令即可。
windows可能不支持export命令,可以直接在命令行中执行:
```
set NODE_OPTIONS=--openssl-legacy-provider
```
也可以切换nodejs版本,使用nvm管理nodejs版本,切换到nodejs16,然后重试。
### shell 脚本
#!/bin/bash
host="$1"
remotedir="/data/$1/"
serviceName="${host//./_}"
if [ "$1" == "" ]; then
echo "please enter host,eg:www.example.com"
exit 1
fi
if [ ! -d "config/$1" ]; then
echo "config/$1 not exists"exit 1
fi
export LC_CTYPE="en_US.UTF-8"
result=$(ssh root@$host "if [ ! -d $remotedir ]; then echo 0; else echo 1; fi")
if [ "$result" -eq 0 ]; then
echo "remote directory[$remotedir] not exists"
exit 1
else
echo "remote directory[$remotedir] check accepted"
fi
function upload_zip() {
echo "[step4] upload zip file ..."
scp -r $1 root@$host:$remotedir
filez=$(basename $1)
echo "filez:$filez"
shellcheck disable=SC2087
ssh root@$host <
print ssh info
cd $remotedir
echo "================= Login ssh success, start update ... ================"
echo "[ssh] Current path:"
pwd
echo "========= Files list ============="
ls -ahl
echo "=================================="
stop docker compose
if [ -d "production" ]; then
echo "[ssh] stop docker compose ..."
cd production
docker compose -p $serviceName down
if [ $? -eq 0 ]; then
echo "[ssh] docker compose -p $serviceName down success"
cd ..
rm -rf production
else
echo "[ssh] docker compose -p $serviceName down error"
exit 1
fi
fi
unzip and move files
echo "[ssh] unzip $filez ..."
mkdir production
unzip -q $filez -d production
mv production// production/
start docker compose
cd production
echo "[ssh] start docker compose ..."
docker compose -p $serviceName up -d 2>&1
update nginx cert
if [ -n "\$(ls -A cert/)" ]; then
echo "[ssh] update nginx cert ..."
if [ ! -d /etc/nginx/cert ]; then
mkdir -p /etc/nginx/cert
fi
cp cert/* /etc/nginx/cert/
fi
update nginx config
if [ -f "$host.conf" ]; then
echo "[ssh] update nginx config ..."
cp $host.conf /etc/nginx/conf.d
nginx -t
if [ $? -eq 0 ]; then
service nginx reload
else
echo -e "[ssh]\e[31mNginx check error\e[0m"
fi
fi
eeooff
}
if [ "$2" == "rollback" ]; then
echo "start rollback ..."
if [ "$3" == "" ]; then
echo "please enter version,eg:www.example.com rollback <1bede1-210801>"
exit 1
fi
upload_zip "packages/$1/$3.zip"
exit 0
fi
hash=$(git rev-parse --short=6 HEAD)
time=$(date +%y%m%d)
output="${hash}-${time}"
package="packages/$1/$output"
zipfile="$output.zip"
echo "[step1] mkdir $package ..."if [ -f "packages/$1/$zipfile" ]; then
echo "packages/$1/$zipfile is exist,continue will overwrite it,continue? [y/n]"read -r input
if [ "$input" != "y" ]; then
exit 1
fi
fi
if [ ! -d "$package" ]; then
set -x
mkdir -p "$package"
set +x
else
echo "$package is exist,continue will overwrite it,continue? [y/n]"read -r input
if [ "$input" != "y" ]; then
exit 1
fi
set -x
rm -rf "$package"
mkdir -p "$package"
set +x
fi
echo "[step2] copy files ..."
set -x
cp -r deploy/* "packages/$1/$output"
cp config/"$1"/docker.admin.yaml "$package/api/adm/"
cp config/"$1"/docker.app.yaml "$package/api/app/"
cp config/"$1"/docker-compose.yaml "$package/"
cp config/"$1"/"$1".conf "$package/$1.conf"
cp -r config/"$1"/cert "$package/cert"
shellcheck disable=SC2038
find $package/ui/admui/static -name "*.js"|xargs sed -i '' 's/wwwexampletplcom/'"$1"'/g'
shellcheck disable=SC2038
find $package/ui/pcui/static -name "*.js"|xargs sed -i '' 's/wwwexampletplcom/'"$1"'/g'
shellcheck disable=SC2038
find $package/ui/wx/dist -name "*.js" |xargs sed -i '' 's/demo.tonyhr.cn/'"$1"'/g'
set +x
if [ "$2" == "stop" ]; then
echo "waiting need change files,finished? [any key continue]"
read -r input
elif [ "$2" == "pre" ]; then
exit 0
fi
echo "[step3] zip files ..."
cd "packages/$1/" || exit 1
zip deploy files
zip -q -r "$zipfile" "$output/"
echo "info:zip finished"
rm -rf "$output"
shellcheck disable=SC2218
upload_zip "$zipfile"
### Makefile
.PHONY: all build run gotool install ui admui pcui wx api object clean help
all: gotool build
build:
make clean
make api
make ui
api:
@if [ ! -d ./deploy/api/adm ];then mkdir -p ./deploy/api/adm;fi
@if [ ! -d ./deploy/api/app ];then mkdir -p ./deploy/api/app;fi
cd ./api && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o ../deploy/api/adm/admapi ./admin/server/
cd ./api && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o ../deploy/api/app/appapi ./app/server/
ui:
make admui
make pcui
make wx
admui:
if [ ! -d ./deploy/ui ];then mkdir -p ./deploy/ui;fi
if [ -d ./deploy/ui/admui ];then rm -rf ./deploy/ui/admui;fi
mkdir ./deploy/ui/admui
cd ./ui/admui && yarn build
cp -r ./ui/admui/build/* ./deploy/ui/admui
pcui:
if [ ! -d ./deploy/ui ];then mkdir -p ./deploy/ui;fi
if [ -d ./deploy/ui/pcui ];then rm -rf ./deploy/ui/pcui;fi
mkdir ./deploy/ui/pcui
cd ./ui/pcui && yarn build
cp -r ./ui/pcui/dist/* ./deploy/ui/pcui
wx:
if [ ! -d ./deploy/ui ];then mkdir -p ./deploy/ui;fi
if [ -d ./deploy/ui/wx ];then rm -rf ./deploy/ui/wx;fi
mkdir ./deploy/ui/wx
cd ./ui/wx && yarn build:mp-weixin
cp -r ./ui/wx/dist ./deploy/ui/wx
object:
@echo "Enter object domain:"
@read -r objectName && \
export objectName=$$objectName; \
echo "Enter admin api port:"; \
read -r adminPort && \
export adminPort=$$adminPort; \
echo "Enter app api port:"; \
read -r appPort && \
export appPort=$$appPort; \
echo "\nenv info => domain:$$objectName adminPort:$$adminPort appPort:$$appPort" && \
if [ ! -d ./config/$$objectName ];then mkdir -p ./config/$$objectName;fi && \
cp ./api/admin/server/config.docker.yaml ./config/$$objectName/docker.admin.yaml && \
cp ./api/app/server/config.docker.yaml ./config/$$objectName/docker.app.yaml && \
cp ./api/docker-compose.yaml ./config/$$objectName/docker-compose.yaml && \
cp ./nginx/nginx.conf ./config/$$objectName/$$objectName.conf && \
cd ./config/$$objectName && \
if [ ! -d ./cert ];then mkdir cert;fi && \
echo "\nfile created success!" && \
ls -l && \
sed -i '' 's/{DOMAIN}/'"$$objectName"'/g' docker.admin.yaml docker.app.yaml $$objectName.conf docker-compose.yaml
&& \
sed -i '' 's/{ADM_PORT}/'"$$adminPort"'/g' docker.admin.yaml docker.app.yaml $$objectName.conf docker-compose.yaml
&& \
sed -i '' 's/{APP_PORT}/'"$$appPort"'/g' docker.admin.yaml docker.app.yaml $$objectName.conf docker-compose.yaml
install:
make build
clean:
@if [ -d deploy/api ] ; then rm -rf deploy/api ; fi
@if [ -d deploy/ui ] ; then rm -rf deploy/ui ; fi
```