[转帖]自动化运维:一键自动化脚本-shell
https://www.cnblogs.com/luoahong/articles/8456203.html
shell函数
1、分别在服务器和客户端上创建www用户
|
1
2
|
useradd wwwid wwww |
- 所有的web服务,都应该使用普通用户,所有的web服务都不应该监听80端口,除非负载均衡。8080
- 普通用户能启动80端口吗?通过和科技,比如给命令设置suid
- 生产指定uid
2、保证www用户登录其他的节点都不要输入密码
服务器端:
|
1
2
3
4
5
6
7
8
9
10
|
[root@node1 ~]# useradd www[root@node1 ~]# id www[root@node1 ~]# passwd www[root@node1 ~]# su www[root@node1 ~]# cd /home/www/[www@node1 ~]$ ssh-copy-id -i .ssh/id_rsa.pub www@172.16.14.116[www@node1 ~]$ ssh 172.16.14.116Last failed login: Sat Jan 13 09:56:41 CST 2018 from 172.16.14.115 on ssh:nottyThere were 3 failed login attempts since the last successful login.Last login: Sat Jan 13 09:23:02 2018 |
客户端:
|
1
2
3
4
5
6
7
8
9
10
|
[root@node2 ~]# useradd www[root@node2 ~]# id www[root@node2 ~]# passwd www[root@node2 ~]# su www[root@node2 ~]# cd /home/www/[www@node2 ~]$ ssh-copy-id -i .ssh/id_rsa.pub www@172.16.14.115[www@node2 ~]$ ssh 172.16.14.115Last failed login: Sat Jan 13 09:56:41 CST 2018 from 172.16.14.115 on ssh:nottyThere were 3 failed login attempts since the last successful login.Last login: Sat Jan 13 09:23:02 2018 |
3、写一个复杂的脚本
先把框架写出来,使用echo来测试框架的流程是否正确
|
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
|
#!/bin/bash # Shell Env SHELL_NAME="deploy.sh" SHELL_DIR="/home/www" SHELL_LOG="{SHELL_DIR}/${SHELL_NAME}.log" # Code Env CODE_DIR="/deploy/code/deploy/" TMP_DIR="/deploy/config" TAR_DIR="/deploy/tar" LOCK_FILE="/tmp/deploy.lock" usage(){ echo $"Usage: $0[ deploy|rollback]" } shell_lock(){ touch ${LOCK_FILE} } shell_unlock(){ rm -f ${LOCK_FILE} } code_get(){ echo code_get; sleep 2; } code_build(){ echo code_build; sleep 2; } code_config(){ echo code_config; sleep 2; } code_tar(){ echo code_tar; sleep 2; } code_scp(){ echo code_scp; sleep 1; } cluster_node_remove(){ echo cluster_node_remove; sleep 1; } code_deploy(){ echo code_deploy; } config_diff(){ echo config__diff; } code_test(){ echo code_test; } cluster_node_in(){ echo cluster_node_in; } main(){ if [ -f $LOCK_FILE ];then echo "Deploy is running"&& exit; fi DEPLOY_METHOD=$1 case $DEPLOY_METHOD in deploy) shell_lock; code_get; code_build; code_config; code_tar; code_scp; cluster_node_remove; code_deploy; config_diff; code_test; cluster_node_in; shell_unlock; ;; rollback) shell_lock; rollback; shell_unlock; ;; *) usage; esac } |
4、什么也没提示?在末尾添加 man $1
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
main(){ DEPLOY_METHOD=$1 case $DEPLOY_METHOD in deploy) shell_lock; ;; rollback) shell_lock; ;; *) usage; esac}main $1 |
本节小结:
1、凡是不记录日志的脚本就是耍流氓

2、这个脚本能不能多个人同时执行?
1、最好不要,但是运维团队有很多人,我如何知道别人有没有执行?
答:我写一个锁文件

1、锁文件放那?
答:放在/tmp/deploy.lock" 因为放在下www没有权限
2、系统的锁文件放哪里?
|
1
|
/var/run/lock |
3、看不出来?
答:sleep60秒

4、不是脚本的$1匙函数的$1

5、在两台电脑上都要用到所以定义为变量

2、功能实现
1、日志函数
|
1
2
3
4
5
6
7
8
9
10
11
|
#Date/Time VeriablesLOG_DATE='date "+%Y-%m-%d"'LOG_TIME='date "+%H-%M-%S"'CDATE=$(date "+%Y-%m-%d")CTIME=$(date "+%H-%M-%S")....writelog(){ LOGINFO=$1 echo "${CDATE} ${CTIME}: ${SHELL_NAME}: ${LOGINFO}" >> ${SHELL_LOG}} |
1、希望在很多地方记录日志
echo一行,写到一个文件里,记日志还要记时间
方法1:写一个日志的函数,每次调用这个函数
方法2:在每一个函数里写一个echo,然后写在那个位置,还要记时间
2、日志函数的好处?
- 这个函数可以复制,以后写别的脚本直接改改就可以
- 每一个函数里都写一个函数
3、shell是如何解析的?
从上倒下逐行执行
4、遇到函数怎么办?
先加载不执行
5、日志的内容从哪来?
从参数来:$1
6、脚本名称:
当前日期+脚本名称+日志内容
难保你以后会写在一起所以要区分开
7、时间是不是不能变?
我就不需要它变:
1、打包的时候不能变,包里有有日期和时间包名不能变
2、打包如何命名?
是scp时间不对,包就找不着了
|
1
2
|
LOG_DATE='date "+%Y-%m-%d"'LOG_TIME='date "+%H-%M-%S"' |
- 一个是让执行 记日志用的
- 一个不让执行 做别的用处
- 已经执行了,在后面就不变了
2、get代码函数
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#Code EnvPRO_NAME="web-demo"CODE_DIR="/deploy/code/web-demo"CONFIG_DIR="/deploy/config/web-demo"TMP_DIR="/deploy/tmp"LOCK_FILE="/tmp/deploy.lock".......code_get(){ writelog "code_get"; cd $CODE_DIR && echo "git pull" cp -r ${CODE_DIR} ${TMP_DIR}/ API_VERL=$(git show |grep commit | cut -d ' ' -f2) API_VER=$(echo ${API_VERL:0:6}) |
1、代码应该放在那?
放在CODE_DIR="/deploy/code/web-demo"目录下
2、配置文件能直接放CODE_DIR这吗?
不能,专门用于git更新的目录
如果你把文件拷贝到这里,所有的包里面都有这个文件
一不小心多放了一个,那个可不会pull
3、怎样区分是仓库的还是我copy过来的?
也能区分 看git状态,本地状态 正常区分不了
更新完之后copy走,放着也行出故障了你就知道是什么意思了!
4、复制到哪?
TMP_DIR
5、为什么对web-demo要重命名?
- 复制过去要重命名
- 打包的时候还要重命名
- 每次都覆盖那就乱了
6、要怎样重命名?
时间+版本号?
1、svn怎样获取版本号?
2、git如何获取版本号?
API_VERL=$(git show |grep commit | cut -d ' ' -f2)
3、配置文件函数
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#Code EnvPRO_NAME="web-demo"CODE_DIR="/deploy/code/web-demo"CONFIG_DIR="/deploy/config/web-demo"TMP_DIR="/deploy/tmp"LOCK_FILE="/tmp/deploy.lock"......code_config(){ writelog "code_config" /bin/cp -r ${CONFIG_DIR}/base/* ${TMP_DIR}/"${PRO_NAME}" PKG_NAME="${PKG_NAME}"_"$API_VER"_"${CDATE}-${CTIME}" cd ${TMP_DIR} && mv ${PKG_NAME} ${PKG_NAME}}} |
1、我是哪个项目的配置文件?
|
1
|
CONFIG_DIR="/deploy/config/web-demo" |
2、为什么加/bin/cp -r?
|
1
|
/bin/cp -r ${CONFIG_DIR}/base/* ${TMP_DIR}/"${PRO_NAME}" |
1、有可能我文件下还有目录呢!
2、我拷贝的那个目录下有那个配置文件
有一测试有权限,犯二提交了一个相同的配置文件 你没有覆盖连到测试库了
大家打开的都是测试的库
开发可以错,测试可以错,运维不可以错 为什么你上线的时候也没发现?
每一个小细节都是有意义不是瞎写
3、复制和打包可以放在一个里面,为什么把包名做成一个变量?
- 很多地方都用到
- 包名很长
- 包名本身也包含变量
4、为什么要全写成变量
因为不只为这一个脚本,写别的脚本改改就可以啦!
5、为什么tmp需要定期进行清理?
部署几个月可以,时间久磁盘就满了
有时间了就好删除了,解决了各种方式
只有版本号你怎样删?把15年的全删了
4、打包函数
|
1
2
3
4
5
|
code_tar(){ writelog "code_tar" cd ${TMP_DIR} && tar czf ${PKG_NAME}.tar.gz ${PKG_NAME} writelog "${PKG_NAME}.tar.gz"} |
1、为什么要写&&?
函数和函数之间可不知道上一级目录是什么!!!
不单独搞一行,如果目录不存在进去了可能不是你想要的
5、scp到目标服务器
|
1
2
3
4
5
6
7
|
code_scp(){ writelog "code_scp" for node in $PRE_LIST;do for node in $GROUP1_LIST;do scp ${TMP_DIR}/${PKG_NAME}.tar.gz $node:/opt/webroot/ done} |
1、统一用一个包的好处?
完全可以写一个for循环
我要加机器 在列表里加一行
减机器 在列表里减去一行
标准化的好处
2、为什么不能直接写在/opt?
- 没有权限
- 在opt创建一个/opt/webroot/复制到这
6、部署函数
|
1
2
3
4
5
6
7
8
|
group1_deploy(){ writelog "remove from cluster" for node in $GROUP1_LIST;do ssh $node "cd /opt/webroot && tar zxf ${PKG_NAME}.tar.gz" ssh $node "rm -f /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo" done scp ${CONFIG_DIR}/other/192.168.56.12.crontab.xml 192.168.56.12:/webroot/web-demo/crontab.xml} |
1、项目之间应该保持独立才对
2、你的目录放在那?
所有生产的web服务器的家目录都写在/webroot的项目名称下
3、为什么先创建软链接然后在复制差异文件?
路径写的少,要不然你写到解压后的路径下
如果没有生成我就不复制
生产部署的时候,没部署成功结果scp复制过去了
4、第一次手动创建一个因为 没有会报错。
|
1
2
3
4
|
su -wwwcd /webroot/touch web-demo用salt就要先touch文件 |
5、&&不能去掉,因为以后部署时候我要先删除才能软链接
6、一个软连接连一毫秒都花不了
3、脚本扩展
1、每个节点上各装一个apache
|
1
|
yum install httpd -y |
2、修改配置文件以下两处
|
1
|
vim /etc/httpd/conf/httpd.conf |

1、测试函数
|
1
2
3
4
5
6
7
8
|
url_test(){ URL=$1 curl -s --head $URL |grep '200 ok' if [ $? -ne 0 ];then shell_unlock; echo "test error" && exit; fi} |
1、测试一能访问就加入集群不能访问就移除集群
2、部署一个测一个通了才能加到集群里
生产是一个组一个组测试
并行和串行相结合
每一个组一个预生产节点
直接部署第二个节点
2、主函数
|
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
|
main(){ if [ -f $LOCK_FILE ]; then echo "Deploy is running" && exit; fi DEPLOY_METHOD=$1 ROLLBACK_VER=$2 case $DEPLOY_METHOD in deploy) shell_lock; code_get; code_build; code_config; code_tar; code_scp; pre_deploy; pre_test; group1_deploy; group1_test; shell_unlock; ;; rollback) shell_lock; rollback $ROLLBACK_VER; shell_unlock; ;; *) usage; esac}main $1 $2 |
1、先判断是否有文件,存在说明有人在执行直接退出
2、你是要部署还是要回滚,要是是部署先锁住脚本
从git上获取文件
进行编译
复制配置文件进去
打包并重命名
scp到所有机器(不分组)
晚上要做一个不算停机维护,所有机器都需要同时重启
涉及到数据一致性
组一部署集群
测试组一集群
4、秒级回滚

在某个地方记住上一个版本是啥,部署把版本写在一个文件里(紧急回滚的一个函数),然后读这个文件
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
rollback(){if [ -z $1 ];then shell_unlock; echo "please input rollback version" && exit;fi case $1 in list) ls -l /opt/webroot/*.tar.gz ;; *) rollback_fun $1 esac} |
部署还是回滚$1,回滚到那个版本是$2
传list的我就列出来,不传我就回滚
我可以只部署预生产,我部署机肯定有我其他的节点没有
|
1
2
3
4
|
rollback_fun(){ for node in $ROLLBACK_LIST;do ssh $node "rm -f /webroot/web-demo && ln -s /opt/webroot/$1 /webroot/web-demo" done |
1、如果list存在我就执行,不存在就结束for循环
2、远程ssh执行命令,引起来才能当成一个,因为中间还有空格

3、脚本的$2传到回滚函数里就是$1

5、gitlab部署和回滚
安装gitlab私有仓库,地址见运维社区gitlab
1、登陆修改root密码
2、备份:每天备份每小时也行
越频繁越好
分布式每个人的本地都有
6、完整脚本构造
|
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
|
#!/bin/bash#Dir Listmkdir -p /deploy/code/web-demomkdir -p /deploy/config/web-demo/basemkdir -p /deploy/config/web-demo/othermkdir -p /deploy/tarmkdir -p /deploy/tmpmkdir -p /opt/webrootmkdir /webrootchown -R www.www /deploychown -R www.www /opt/webrootchown -R www.www /webroot#Node ListPRE_LIST="192.168.56.11"GROUP1_LIST="192.168.56.12"ROLLBACK_LIST="192.168.56.11 192.168.56.12"#Date/Time VeriablesLOG_DATE='date "+%Y-%m-%d"'LOG_TIME='date "+%H-%M-%S"'CDATE=$(date "+%Y-%m-%d")CTIME=$(date "+%H-%M-%S")#Shell EnvSHELL_NAME="deploy_all.sh"SHELL_DIR="/home/www/"SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log"#Code EnvPRO_NAME="web-demo"CODE_DIR="/deploy/code/web-demo"CONFIG_DIR="/deploy/config/web-demo"TMP_DIR="/deploy/tmp"LOCK_FILE="/tmp/deploy.lock"usage(){ echo $"Usage: $0{deploy|rollback[ list|version ]}"}writelog(){ LOGINFO=$1 echo "${CDATE} ${CTIME}: ${SHELL_NAME}: ${LOGINFO}" >> ${SHELL_LOG}}shell_lock(){ touch ${LOCK_FILE}}url_test(){ URL=$1 curl -s --head $URL |grep '200 ok' if [ $? -ne 0 ];then shell_unlock; echo "test error" && exit; fi}shell_unlock(){ rm -f ${LOCK_FILE}}code_get(){ writelog "code_get"; cd $CODE_DIR && echo "git pull" cp -r ${CODE_DIR} ${TMP_DIR}/ API_VERL=$(git show |grep commit | cut -d ' ' -f2) API_VER=$(echo ${API_VERL:0:6})}code_build(){ echo code_Build}code_config(){ writelog "code_config" /bin/cp -r ${CONFIG_DIR}/base/* ${TMP_DIR}/"${PRO_NAME}" PKG_NAME="${PKG_NAME}"_"$API_VER"_"${CDATE}-${CTIME}" cd ${TMP_DIR} && mv ${PKG_NAME} ${PKG_NAME}}}code_tar(){ writelog "code_tar" cd ${TMP_DIR} && tar czf ${PKG_NAME}.tar.gz ${PKG_NAME} writelog "${PKG_NAME}.tar.gz"}code_scp(){ writelog "code_scp" for node in $PRE_LIST;do for node in $GROUP1_LIST;do scp ${TMP_DIR}/${PKG_NAME}.tar.gz $node:/opt/webroot/ done}pre_deploy(){ writelog "remove from cluster" ssh $PRE_LIST "cd /opt/webroot && tar zxf ${PKG_NAME}.tar.gz" ssh $PRE_LIST "rm -f /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo"}pre_test(){ url_test "http://${PRE_LIST}/index.html" echo "add to cluster"}group1_deploy(){ writelog "remove from cluster" for node in $GROUP1_LIST;do ssh $node "cd /opt/webroot && tar zxf ${PKG_NAME}.tar.gz" ssh $node "rm -f /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo" done scp ${CONFIG_DIR}/other/192.168.56.12.crontab.xml 192.168.56.12:/webroot/web-demo/crontab.xml}group1_test(){ url_test "http://192.168.56.12/index.html" echo "add to cluster"}rollback_fun(){ for node in $ROLLBACK_LIST;do ssh $node "rm -f /webroot/web-demo && ln -s /opt/webroot/$1 /webroot/web-demo" done}rollback(){if [ -z $1 ];then shell_unlock; echo "please input rollback version" && exit;fi case $1 in list) ls -l /opt/webroot/*.tar.gz ;; *) rollback_fun $1 esac}main(){ if [ -f $LOCK_FILE ]; then echo "Deploy is running" && exit; fi DEPLOY_METHOD=$1 ROLLBACK_VER=$2 case $DEPLOY_METHOD in deploy) shell_lock; code_get; code_build; code_config; code_tar; code_scp; pre_deploy; pre_test; group1_deploy; group1_test; shell_unlock; ;; rollback) shell_lock; rollback $ROLLBACK_VER; shell_unlock; ;; *) usage; esac}main $1 $2 |
转载地址:https://github.com/unixhot/deploy-shell
[转帖]自动化运维:一键自动化脚本-shell的更多相关文章
- Linux centosVMware 自动化运维认识自动化运维、启动salt相关服务、saltstack配置认证、salt-key命令用法、saltstack远程执行命令、saltstack - grains、saltstack – pillar
一.认识自动化运维 传统运维效率低,大多工作人为完成 传统运维工作繁琐,容易出错 传统运维每日重复做相同的事情 传统运维没有标准化流程 传统运维的脚本繁多,不能方便管理 自动化运维就是要解决上面所有问 ...
- 自动化运维——一键安装MySQL
根据项目需要,前段时间在搞EMM系统各种安装包的自动化部署工作,主要包括一键安装和一键启动\停止功能.总结记录下来,以供后用. 本文主要是自动安装MySQL5.7.11版,Linux版脚本在CentO ...
- 自动化运维——MySQL备份脚本(二)
使用if语句编写MySQL备份脚本 代码: #!/bin/bash #auro backup mysql db #by steve yu #define backup path BAK_DIR=/da ...
- CheungSSH国产自动化运维工具开源Web界面
CheungSSH web2.0 发布文档 CheungSSH 简介 CheungSSH是一款国人自主研发的Linux运维自动化管理服务器软件,秉着为企业降低运营成本,解放管理员双手和自动化生产的理念 ...
- 使用Ansible实现数据中心自动化运维管理
长久以来,IT 运维在企业内部一直是个耗人耗力的事情.随着虚拟化的大量应用.私有云.容器的不断普及,数据中心内部的压力愈发增加.传统的自动化工具,往往是面向于数据中心特定的一类对象,例如操作系统.虚拟 ...
- 技术沙龙|京东云DevOps自动化运维技术实践
自动化测试体系不完善.缺少自助式的持续交付平台.系统间耦合度高服务拆分难度大.成熟的DevOps工程师稀缺,缺少敏捷文化--这些都是DevOps 在落地过程中,或多或少会碰到的问题,DevOps发展任 ...
- 自动化运维工具-Ansible之7-roles
自动化运维工具-Ansible之7-roles 目录 自动化运维工具-Ansible之7-roles Ansible Roles基本概述 Ansible Roles目录结构 Ansible Roles ...
- 自动化运维工具-Ansible之5-流程控制
自动化运维工具-Ansible之5-流程控制 目录 自动化运维工具-Ansible之5-流程控制 playbook条件语句 单条件 多条件 多条件运算 示例 playbook循环语句 with_ite ...
- 自动化运维工具-Ansible之2-ad-hoc
自动化运维工具-Ansible之2-ad-hoc 目录 自动化运维工具-Ansible之2-ad-hoc Ansible ad-hoc Ansible命令模块 Ansible软件管理模块 Ansibl ...
- 真正云原生的智能运维体系,阿里云发布ECS自动化运维套件
云计算的发展,推动了自动化运维.DevOps.AIOps 等趋势的兴起,在业务快速变化的今天,企业希望通过一套自动化运维的专家系统提高运维效率,为业务提供支撑. 传统的方式下,打造一套成熟的 DevO ...
随机推荐
- 赶在520之前,程序员如何用Python送上最特别的“我爱你”表白
摘要:每到情人节.七夕节,不少小伙伴大伙伴们都会遇到这样一个世纪问题--怎么给女朋友/老婆一个与众不同的节日惊喜.今天给大家分享一个独特的表白方法--用"我爱你"拼出心爱人的模样! ...
- 数据库技术丨GaussDB(DWS)数据同步状态查看方法
摘要:针对数据同步状态查看方法,GaussDB(DWS)提供了丰富的系统函数.视图.工具等可以直观地对同步进度进行跟踪,尤其是为方便定位人员使用,gs_ctl工具已集合了大部分相关系统函数的调用,可做 ...
- 共筑数字化未来,金山办公携手华为云完成文档中心和GaussDB适配
摘要:金山办公携手华为云完成金山办公自主研发的"WPS文档中心系统"与华为云GaussDB相互兼容性测试认证,并获得华为云授予的<技术认证书>. 本文分享自华为云社区& ...
- 你好 Java!Solon v1.10.3 发布
相对于 Spring Boot 和 Spring Cloud 的项目: 启动快 5 - 10 倍. (更快) qps 高 2- 3 倍. (更高) 运行时内存节省 1/3 ~ 1/2. (更少) 打包 ...
- Markdown 图片居中显示,增加图片说明
<center> <img src="https://img2023.cnblogs.com/blog/80824/202308/80824-202308081307138 ...
- PPT 商务图表的应用和美化之道
PPT 商务图表的应用和美化之道 折线图 饼图 你认为的图表元素,可能是图表外的元素 https://www.bilibili.com/video/BV1ha411g7f5/?p=11
- .Net Core 开发框架,支持多版本的类库
工具:Visual Studio 2019 1.新建一个 .NET Standard 类库. 2.填写项目名称 3.编辑项目文件 可以看到当前类库默认为 netstandard2.0,而此时其xml标 ...
- SpringBoot Jar 包太大 瘦身 【终极版】
思路,将依赖的第三方jar包,移到启动jar包个面外部加载 jar 包 SpringBoot Jar 包太大 瘦身 [初试]简单应用 SpringBoot Jar 包太大 瘦身 [终极版],建议使用这 ...
- 【软件安装记录篇】本地虚拟机Centos7快速安装MySQL
安装 采用Installing MySQL on Linux Using the MySQL Yum Repository的方式进行安装. 1. 首先下载服务器版本对应的rpm文件,下载地址:[链接] ...
- 开源项目因支持乌克兰遭issue刷屏,网友:别用Nginx,别用元素周期表
大家好,我是DD. 昨天,两条科技界的新闻炸了,一条是关于GitHub发文封锁俄罗斯,一条是关于Oracle暂停俄罗斯所有业务.一个是全球最大的开源软件社区,一个是全球最大的数据库软件厂商.似乎巨头的 ...