spug是一款优秀的自动化运维平台, 这让我们想自动化又向前迈了一步.
在过程中遇到的问题,记录在这里供各位看官参考.
一、远程执行命令问题
利用spug打好包之后,如何分发到应用最终跑的那台主机上去。
这里有三个想法:
1、ssh 发布主机后 执行命令,
例如:
ssh 10.50 "ln -snf /opt/qwert-$SPUG_GIT_TAG.war /opt/eqwe_fi_-spug.war"
对于内置命令不需要写命令的绝对路径,
ssh 10.50 "setsid /usr/lcal/jdk1.8.0_121/bin/java -Xms512m -Xmx1024m ....
对非内置命令需要写绝对路径,这是为何? 这是和 环境变量有关的
2、ssh之后去执行命令
在spug 常规发布中,在目标主机上ssh 发布主机,ssh IP "ls /opt" 这个可以执行出来 。但是 先ssh IP 再执行其他命令就不行
这是在非登录SHELL里执行的。
尝试使用ssh -tt 强制分配一个tty也不行
3、EOT End Of Text.
看下面这个例子,登录到目标主机上去,执行完命令后退出,使用这种方式在需要发布的主机上把打好的包copy过去,然后开始启动流程
ssh user@server /bin/bash <<'EOT' echo "These commands will be run on: $( uname -a )" echo "They are executed by: $( whoami )" EOT
这段shell 写的不是很好,硬编码严重,逻辑也有不严谨的地方。后续持续改进
echo "开始修改包名..............:" mv /opt/MPP/target/MPP.jar /opt/MPP/target/MPP_array_fi_$SPUG_GIT_TAG.jar echo "修改中..............:" sleep 1s if [ $? -eq 0 ] then echo "修改成功.............." else echo "修改失败,请确认.............." fi echo "开始移动包到指定服务器..............:" #todo 2021年7月6日10:03:21 自动免密验证 # ssh 192.168.10.168 /bin/bash << 'EOT' # if [ -d /opt/servers/MPP4 ];then # echo "目录已存在" # else # mkdir -p /opt/servers/MPP4/ # echo "目录创建成功" # fi # EOT scp /opt/MPP/target/MPP_array_fi_$SPUG_GIT_TAG.jar 192.168.10.168:/opt/servers/MPP4 ssh 192.168.10.168 "ln -snf /opt/servers/MPP4/MPP_array_fi_$SPUG_GIT_TAG.jar /opt/servers/MPP4/MPP-spug.jar" # --------------------------------------------- ssh by sscripts start 2021年7月27日09:01:05 ssh root@192.168.10.168 /bin/bash <<'EOT' cd /opt/servers/MPP4/ echo "当前目录为:" pwd PID=$(ps -ef|egrep "MPP"|grep -v egrep|awk '{print $2}') PID_CNT=$(ps -ef|egrep "MPP"|grep -v egrep|awk '{print $2}'|wc -l) if [ $PID_CNT -eq 1 ];then echo "进程已存在,pid: $PID..............:" echo "重启中..............:" ps -ef|egrep "MPP"|grep -v egrep|awk '{print $2}'|xargs kill -9 sleep 10s date +%H:%M:%S PID_CNT1=$(ps -ef|egrep "MPP"|grep -v egrep|awk '{print $2}'|wc -l) if [ $PID_CNT1 -eq 0 ];then echo "......启动命令$$........:" setsid /usr/local/jdk1.8.0_191/bin/java -Djava.rmi.server.hostname=192.168.10.168 -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=18999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Xms1024m -Xmx4096m -jar -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:/aplog/MPP/agc.log -Dspring.profiles.active=prod /opt/servers/MPP4/MPP-spug.jar --server.port=8066 --mq.quartzFlg=Y --etl.quartzFlg=N --mq.alarmQuartzFlg=N --mq.shopId=QQQ >/dev/null & PID1=$(ps -ef|egrep "MPP"|grep -v egrep|awk '{print $2}') echo "重启成功,pid: $PID1..............:" fi else date +%H:%M:%S echo "当前目录为:" pwd echo "启动中..............:" date +%H:%M:%S setsid /usr/local/jdk1.8.0_191/bin/java -Djava.rmi.server.hostname=192.168.10.168 -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=18999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Xms1024m -Xmx4096m -jar -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:/aplog/MPP/agc.log -Dspring.profiles.active=prod /opt/servers/MPP4/MPP-spug.jar --server.port=8066 --mq.quartzFlg=Y --etl.quartzFlg=N --mq.alarmQuartzFlg=N --mq.shopId=QQQ >/dev/null & PID2=$(ps -ef|egrep "MPP"|grep -v egrep|awk '{print $2}') date +%H:%M:%S echo "启动成功,PID为 $PID2..............:" fi EOT date +%H:%M:%S
二、软连接的问题
进入一个软连接目录,如果该目录被重新指向新的链接。
此时在当前目录看到的文件仍旧是旧文件.
cd出去,重新进入该目录文件才更新.
参考:
linux - Pseudo-terminal will not be allocated because stdin is not a terminal - Stack Overflow
三、jdk 版本问题
启动java程序时报如下错误
Exception in thread "main" java.lang.UnsupportedClassVersionError: com/navi/RtmApplication : Unsupported major.minor version 52.0 at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:803) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:449) at java.net.URLClassLoader.access$100(URLClassLoader.java:71) at java.net.URLClassLoader$1.run(URLClassLoader.java:361) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:425) at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:94) at java.lang.ClassLoader.loadClass(ClassLoader.java:358) at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:46) at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
打包机器的的JDK版本和AP服务器的JDK版本不一致导致的
打包环境: /usr/local/jdk1.8.0_144/bin/java
运行环境: /usr/local/jdk1.8.0_191/bin/java
打包环境jdk版本是向下兼容,如果运行环境的版本比打包的新则会报如上错误.
解决: 使用同一个jdk版本打包
--update 2022年8月10日09:57:40
今天在执行脚本模板的时候也同样报这个错误, 这仅仅是远程执行脚本 为何会对jdk版本有要求呢?
其实是因为启动脚本中没有使用java的绝对路径导致的。参考: JAVA版本号的问题 Java版本号与JDK版本_renhq-CSDN博客_jdk与java版本
四、ssh远程连接中传递变量
问题:
解决:
注意双引号才会有变量替换,再复习下shell的解析
五、解决spug 上版卡一直卡主的问题
上版的时候一直卡在检出后发布
这是在检出前打印配置信息解决:
仔细观察发现打印配置文件卡主的地方是第一次出现中文注释的地方。
可以在cat 的时候直接转码
echo "当前配置列表 ......" # iconv -f GBK -t UTF-8 用于转换中文乱码问题 cat ./chot-configs/src/main/resources/application-production.properties | iconv -f GBK -t UTF-8 echo "done"
iconv命令 是用来转换文件的编码方式的,比如它可以将UTF8编码的转换成GB18030的编码,反过来也行。JDK中也提供了类似的工具native2ascii。Linux下的iconv开发库包括iconv_open,iconv_close,iconv等C函数,可以用来在C/C++程序中很方便的转换字符编码,这在抓取网页的程序中很有用处,而iconv命令在调试此类程序时用得着。 -f encoding :把字符从encoding编码开始转换。 -t encoding :把字符转换到encoding编码。 列出当前支持的字符编码: iconv -l 将文件file1转码,转后文件输出到fil2中: iconv file1 -f EUC-JP-MS -t UTF-8 -o file2 这里,没-o那么会输出到标准输出。
六、新建应用踩坑记
模板已经算很完善了,为啥还会报错呢?发现是新建的应用中有一个空格,导致后面的命令执行失败。linux中对于名称这类的建议不要使用空格。如果非要用,那引用的时候需要加上引号。这个win是完全不同的
七、docker 容器重启登录报错的问题
docker 容器重启之后提示mysql报错。很明显chot这个账户访问mysql的权限被拿掉了,不知谁何时拿掉了chot的访问权限。解决:
1、进入容器查看自定义mysql配置
more /data/spug/spug_api/spug/overrides.py DEBUG = True ALLOWED_HOSTS = ['127.0.0.1'] DATABASES = { 'default': { 'ATOMIC_REQUESTS': True, 'ENGINE': 'django.db.backends.mysql', 'NAME': 'spug', 'USER': 'chot', 'PASSWORD': '', 'HOST': '10.50.10.180', 'OPTIONS': { 'charset': 'utf8mb4', 'sql_mode': 'STRICT_TRANS_TABLES', } } }
2、查看mysql数据库的user表权限分配。
SELECT Host, `User`, Password, Select_priv, Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv, Reload_priv, Shutdown_priv, Process_priv, File_priv, Grant_priv, References_priv, Index_priv, Alter_priv, Show_db_priv, Super_priv, Create_tmp_table_priv, Lock_tables_priv, Execute_priv, Repl_slave_priv, Repl_client_priv, Create_view_priv, Show_view_priv, Create_routine_priv, Alter_routine_priv, Create_user_priv, Event_priv, Trigger_priv, Create_tablespace_priv, ssl_type, ssl_cipher, x509_issuer, x509_subject, max_questions, max_updates, max_connections, max_user_connections, plugin, authentication_string, password_expired FROM mysql.`user`; delete from mysql.user where host='10.50.10.185' AND `User` = 'root' ; # 该语句用于为 root 用户授予所有权限,其中 *.* 表示所有数据库及表,'%' 表示任意主机,123456 是该用户的密码,grant with grant option 允许 root 用户给其它用户授权。 grant all privileges on *.* to chot@'10.50.10.185' identified by 'chot123' with grant option; flush privileges;
刚开始再想是给容器ip的权限还是宿主机,后来发现给宿主机的ip访问权限即可。
八、spug 升级v3
注意三点
1、从私服镜像
2、需要docker compose环境
3、绑定挂载卷先创建,不要覆盖旧版本的目录。(切记)
mkdir -p /data/spugv3/{mysql,service,repos}
安装步骤
准备docker compose文件
vi docker-compose.yml
version: "3.3" services: db: image: chot-harbor.prod.com/mariadb:10.8.2 container_name: spug-db restart: always command: --port 3306 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci volumes: - /data/spugv3/mysql:/var/lib/mysql environment: - MYSQL_DATABASE=spug - MYSQL_USER=spug - MYSQL_PASSWORD=spug.cc - MYSQL_ROOT_PASSWORD=spug.cc spug: image: chot-harbor.prod.com/openspug/spug-service container_name: spug privileged: true restart: always volumes: - /data/spugv3/service:/data/spug - /data/spugv3/repos:/data/repos ports: # 如果80端口被占用可替换为其他端口,例如: - "8000:80" - "80:80" environment: - MYSQL_DATABASE=spug - MYSQL_USER=spug - MYSQL_PASSWORD=spug.cc - MYSQL_HOST=db - MYSQL_PORT=3306 depends_on: - db
启动容器
docker-compose up -d
[root@p1edaspk02 /data/spugv3]#ll total 16 -rw-r--r-- 1 root root 903 Feb 15 14:42 docker-compose.yml drwxr-xr-x 6 ods ssh_keys 4096 Feb 15 14:42 mysql drwxr-xr-x 2 root root 4096 Feb 15 14:38 repos drwxr-xr-x 7 root root 4096 Nov 22 22:40 service [root@p1edaspk02 /data/spugv3]#docker-compose up -d Pulling spug (10.50.10.185/spug/openspug/spug-service:)... latest: Pulling from spug/openspug/spug-service 2d473b07cdd5: Pull complete bdb0935e8d37: Pull complete 1d6205a807d3: Pull complete 59f34e576c77: Pull complete 02c1c97d4b1b: Pull complete 0c036ff8db69: Pull complete d29ea661ea93: Pull complete a771e1af3d9c: Pull complete 4c5ea51c617e: Pull complete 50f24e73c5d1: Pull complete 7a6fe3f468e0: Pull complete 5925d2f1942b: Pull complete 1725bcbd6235: Pull complete 6d9da4e99b24: Pull complete Digest: sha256:56917efe2ab423698ab83d03abd3fc57ec33988003cba7e5634b28c04ab8bb5b Status: Downloaded newer image for 10.50.10.185/spug/openspug/spug-service:latest Creating spug-db ... done Creating spug ... done
以下操作会创建一个用户名为 admin
密码为 Admin123 的管理员账户,可自行替换管理员账户/密码。
docker exec spug init_spug admin Admin123456
#docker exec spug init_spug admin Admin123 Migrations for 'account': data/spug/spug_api/apps/account/migrations/0001_initial.py - Create model History - Create model Role - Create model User - Add field created_by to role Migrations for 'alarm': data/spug/spug_api/apps/alarm/migrations/0001_initial.py - Create model Alarm - Create model Group - Create model Contact Migrations for 'config': data/spug/spug_api/apps/config/migrations/0001_initial.py - Create model Service - Create model Environment - Create model ConfigHistory - Create model Config Migrations for 'exec': data/spug/spug_api/apps/exec/migrations/0001_initial.py - Create model Transfer - Create model ExecTemplate - Create model ExecHistory Migrations for 'home': data/spug/spug_api/apps/home/migrations/0001_initial.py - Create model Navigation - Create model Notice Migrations for 'host': data/spug/spug_api/apps/host/migrations/0001_initial.py - Create model Host - Create model HostExtend - Create model Group Migrations for 'monitor': data/spug/spug_api/apps/monitor/migrations/0001_initial.py - Create model Detection Migrations for 'notify': data/spug/spug_api/apps/notify/migrations/0001_initial.py - Create model Notify Migrations for 'schedule': data/spug/spug_api/apps/schedule/migrations/0001_initial.py - Create model History - Create model Task Migrations for 'setting': data/spug/spug_api/apps/setting/migrations/0001_initial.py - Create model Setting - Create model UserSetting Migrations for 'app': data/spug/spug_api/apps/app/migrations/0001_initial.py - Create model App - Create model Deploy - Create model DeployExtend1 - Create model DeployExtend2 Migrations for 'repository': data/spug/spug_api/apps/repository/migrations/0001_initial.py - Create model Repository Migrations for 'deploy': data/spug/spug_api/apps/deploy/migrations/0001_initial.py - Create model DeployRequest Operations to perform: Apply all migrations: account, alarm, app, config, deploy, exec, home, host, monitor, notify, repository, schedule, setting Running migrations: Applying account.0001_initial... OK Applying alarm.0001_initial... OK Applying config.0001_initial... OK Applying app.0001_initial... OK Applying repository.0001_initial... OK Applying deploy.0001_initial... OK Applying exec.0001_initial... OK Applying home.0001_initial... OK Applying host.0001_initial... OK Applying monitor.0001_initial... OK Applying notify.0001_initial... OK Applying schedule.0001_initial... OK Applying setting.0001_initial... OK 初始化/更新成功 创建用户成功
登录
九、如何使用配置中心
配置中心的时候可以少创建很多应用,如果一个应用有很多环境,可以使用配置中心这个功能,在应用配置中动态获取配置。
目前项目中环境分类并不是很多,没有使用该功能。后续持续关注,必要时可以引入配置中心这个功能。
获取配置中心的数据 并写入环境变量 # 应用发布前 请求地址:/api/apis/config/ 请求方法: GET curl -so .env http://spug.prod:8099/api/apis/config/?apiToken=$SPUG_API_TOKEN curl "http://spug.prod:8099/config/?apiKey=JLV8IGO0DhoxcM7I&app=order&env=test" 如何获取? /api/apis/config/ curl "http://spug.prod:8099/api/apis/config/?apiKey=JLV8IGO0DhoxcM7I&app=rptetl&env=container"