Puppet 部署应用(Puppet deployment application)

news2024/11/14 16:15:23

  💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。

推荐:Linux运维老纪的首页,持续学习,不断总结,共同进步,活到老学到老
导航剑指大厂系列:全面总结 运维核心技术:系统基础、数据库、网路技术、系统安全、自动化运维、容器技术、监控工具、脚本编程、云服务等。
常用运维工具系列:常用的运维开发工具, zabbix、nagios、docker、k8s、puppet、ansible等
数据库系列:详细总结了常用数据库 mysql、Redis、MongoDB、oracle 技术点,以及工作中遇到的 mysql 问题等
懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作
数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂
非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨

自动化运维之Puppet 部署应用
技能目标
-
熟悉 Puppet 工作原理
-
掌握 Puppet 部署应用配置方法

4.1 案例一分析

4.1.1 案例概述

作为一名系统管理员,维护服务器正常运行是最基本的职责。在管理几台到几十
台服务器时,大部分管理员喜欢写自己的小工具来维护。但是随着服务器数量的增多,
任务量也逐渐增加,这时就需要简洁的、强大的框架来完成系统管理任务。
为实现这一目的,引入一批工具。这批工具是可编程的,系统管理员只需要为
这批工具写上几行代码,它便会自动完成所有的工作,Puppet 就是这批运维自动化
工具中的其中一种。在一些大型互联网企业中,Puppet 运维自动化工具管理着几百
甚至上千台服务器,它可以针对多台服务器进行统一操作,如部署统一软件、进行统
一上线维护等,而且能够快速完成上线部署,减少人力并降低人力误操作风险。

4.1.2 案例前置知识点

1. Puppet 工作原理

Puppet 的目的是让管理员只集中于要管理的目标,而忽略实现的细节。Puppet
可以在单机上使用,也可以以 C/S 结构使用。在大规模使用 Puppet 的情况下,通常使
C/S 结构。在这种结构中 Puppet 客户端只运行 Puppet ClientPuppet 服务器端
只运行 Puppet Master
Puppet 管理工具的工作流程如图 4.1 所示。
4.1 Puppet 工作流程
1)客户端 Puppet 调用 Facter 工具(Facter 是通过 SSL 加密收集及检测分析
客户端配置信息的一个工具),Facter 探测出主机的一些变量,如主机名、内存大小、
IP 地址等。Puppet 把这些信息通过 SSL 连接发送到服务器端。
2)服务器端的 Puppet Master 通过 Facter 工具分析检测客户端的主机名,然
后找到项目主配置文件 manifest 里面对应的 node 配置, 并对该部分内容进行解析。
Facter 发送过来的信息可以作为变量处理,node 牵涉到的代码才解析,其他没牵涉
的代码不解析。解析分为几个阶段,首先进行语法检查。如果语法没错,就继续解析。
解析的结果生成一个中间的伪代码,然后把伪代码发给客户端。
3)客户端接收到伪代码并且执行,客户端把执行结果发送给服务器。
4)服务器端把客户端的执行结果写入日志。

2. Puppet 工作中的注意事项

Puppet 工作过程中,有以下两点值得注意。
1)为了保证安全,Client Master 之间是基于 SSL 和证书的,只有经 Master
证书认证的 Client 才能与 Master 通信。
(2Puppet 会让系统保持在人们所期望的某种状态并一直维持下去。例如检测
某个文件并保证其一直存在,保证 SSH 服务始终开启,如果文件被删除了或者 SSH
服务被关闭了,Puppet 下次执行时(默认 30 分钟),会重新创建该文件或者启动 SSH
服务。

4.1.3 案例环境

1. 本案例实验环境

本案例主要演示批量管理客户端 SSH 服务,案例实验中使用的四台服务器均采
CentOS7.3 系统版本且图形化安装,要求能上互联网,Selinux 和防火墙均已关闭。
本案例的拓扑图如下 4.2 所示。
4.2 实验拓扑
服务器具体信息如表 4-1 所示。
4-1 服务器具体配置信息
角色主机名IP 地址主要软件
mastermaster.puppet.com192.168.0.111Puppet-server
clientclient01.puppet.com192.168.0.112Puppet
clientclient02.puppet.com192.168.0.113Puppet
ntpntp.puppet.com192.168.0.114ntp

2. 案例需求

使用 Puppet 批量修改客户端 SSH 服务端口。
3. 案例实现思路1)环境准备工作;
2)安装 Puppet Master Puppet Client
3)配置测试节点;
4)客户端主动拉取和服务端主动推送。

4.2 案例一实施

4.2.1 Puppet 安装与部署

1. 规划服务器主机名

在小规模 Puppet 环境下,一般是修改/etc/hosts 文件实现服务通过主机名进行通
信,然而上千台服务器,需要搭建自己的 DNS 服务器来实现服务通过主机名进行通
信。此实验我们通过修改/etc/hosts 文件来实现。
[root@node1 ~]# hostnamectl set-hostname master.puppet.com
[root@node1 ~]# bash
[root@master ~]# hostname
master.puppet.com
另外,三台服务器上分别修改主机名。
[root@node2 ~]# hostnamectl set-hostname client01.puppet.com
[root@node3 ~]# hostnamectl set-hostname client02.puppet.com
[root@node4 ~]# hostnamectl set-hostname ntp.puppet.com
在 四 台 服 务 器 的 /etc/hosts 文 件 中 都 添 加 以 下 几 行 地 址 解 析 记 录 。 以
master.puppet.com 主机为例进行操作演示。
[root@master ~]# cat << EOF >> /etc/hosts
192.168.0.111 master.puppet.com
192.168.0.112 client01.puppet.com
192.168.0.113 client02.puppet.com
192.168.0.114 ntp.puppet.com
EOF

2. 搭建时间服务器

由于 Puppet 使用的 SSL 证书依赖时间同步,所以需要搭建 NTP 服务器。
(1)搭建 NTP Server
[root@ntp ~]# yum install -y ntp
[root@ntp ~]# vim /etc/ntp.conf
\\添加以下两行
server 127.127.1.0
fudge 127.127.1.0 stratum 8
上述配置的作用是当/etc/ntp.conf 中定义的 server 都不可用时,将使用 local
间作为 NTP 服务提供给 NTP 客户端。修改完/etc/ntp.conf 文件后,可启动 NTP 服务。
[root@ntp ~]# systemctl start ntpd
[root@ntp ~]# systemctl enable ntpd
//设置开机自启动
Created
symlink
from
/etc/systemd/system/multi-user.target.wants/ntpd.service
to
/usr/lib/systemd/system/ntpd.service.
[root@ntp ~]# ntpstat
//查看时间同步状态
synchronised to local net (127.127.1.0) at stratum 9
time correct to within 7948 ms
polling server every 64 s

(2)节点同步时间

其余三台主机都要执行时间同步操作,下面仅以在 master.puppet.com 主机为例
进行演示。
[root@master ~]# yum install -y ntp
[root@master ~]# ntpdate ntp.puppet.com
3 Jul 10:13:16 ntpdate[3853]: adjust time server 192.168.0.114 offset -0.004241 sec

3. 安装 Puppet Master

从 官 网 https://yum.puppetlabs.com/el/7/products/x86_64/ 下 载 Puppet
puppetlabs-release-7-12.noarch.rpm 软件包,上传到 master.puppet.com 服务器上。

(1)安装 puppetlabs 源

[root@master ~]# rpm -ivh puppetlabs-release-7-12.noarch.rpm
警 告 : puppetlabs-release-7-12.noarch.rpm: V4 RSA/SHA1 Signature, 密 钥 ID 4bd6ec30:
NOKEY
准备中...
################################# [100%]
正在升级/安装...
1:puppetlabs-release-7-12
################################# [100%]

(2)安装并启动 Puppet 服务端

[root@master ~]# yum install -y puppet-server
[root@master ~]# systemctl start puppetmaster
[root@master ~]# systemctl enable puppetmaster
Created symlink from /etc/systemd/system/multi-user.target.wants/puppetmaster.service to
/usr/lib/systemd/system/puppetmaster.service.

4. 安装 Puppet Client

两台客户端安装并配置 Puppet,下面仅以 client01.puppet.com 主机为例进行操
作演示。从官网下载 Puppet puppetlabs-release-7-12.noarch.rpm,上传到两台客
户端服务器上。

(1)安装 puppetlabs 源

[root@client01 ~]# rpm -ivh puppetlabs-release-7-12.noarch.rpm
警 告 : puppetlabs-release-7-12.noarch.rpm: V4 RSA/SHA1 Signature, 密 钥 ID 4bd6ec30:
NOKEY
准备中...
################################# [100%]
正在升级/安装...
1:puppetlabs-release-7-12
################################# [100%]

(2)客户端安装 Puppet

[root@client01 ~]# yum install -y puppet

(3)修改客户端配置文件

/etc/puppet/puppet.conf 文 件 中 的 [main] 标 题 下 添 加 “server =
master.puppet.com”配置字段用于设置 Puppet Master 的域名。
[root@client01 ~]# vim /etc/puppet/puppet.conf
server = master.puppet.com

5. 注册

(1)客户端申请注册

在两台客户端上申请注册,下面以 client01.puppet.com 主机为例进行操作演示。
[root@client01 ~]# puppet agent --server=master.puppet.com --no-daemonize --verbose
Info: Creating a new SSL key for client01.puppet.com
Info: Caching certificate for ca
Info: csr_attributes file loading from /etc/puppet/csr_attributes.yaml
Info: Creating a new SSL certificate request for client01.puppet.com
Info:
Certificate
Request
fingerprint
(SHA256):
42:17:0F:38:2F:2E:71:43:45:36:57:C3:B2:B8:23:42:29:01:8F:60:B8:CC:4E:0E:5B:48:EA:9E:F9:86:
34:51
Info: Caching certificate for ca
等待一会儿,可以按 Ctrl+C 结束,从服务器端查看到申请信息。
[root@master ~]# puppet cert --list //Master 端查看申请注册的客户端
"client01.puppet.com"
(SHA256)
E1:66:62:91:8D:98:99:C4:8D:F0:20:64:A6:95:1F:93:B9:95:73:6A:7A:B5:85:18:C4:43:9B:FF:E5:61:
37:AF
"client02.puppet.com"
(SHA256)
E8:ED:80:B2:14:B4:3B:41:C5:4E:EC:97:7A:96:52:1F:36:EA:03:5A:FD:8B:AD:12:86:3A:3B:D6:D2:3
7:0C:29

(2)完成注册

Master 上,将所有申请未注册的客户端进行注册。
[root@master ~]# puppet cert sign --all
Notice: Signed certificate request for client01.puppet.com
Notice:
Removing
file
Puppet::SSL::CertificateRequest
client01.puppet.com
at
'/var/lib/puppet/ssl/ca/requests/client01.puppet.com.pem'
Notice: Signed certificate request for client02.puppet.com
Notice:
Removing
file
Puppet::SSL::CertificateRequest
client02.puppet.com
at
'/var/lib/puppet/ssl/ca/requests/client02.puppet.com.pem'
注册成功后,可以通过目录去查看已经注册的客户端。
[root@master ~]# ll /var/lib/puppet/ssl/ca/signed/
总用量 12
-rw-r--r-- 1 puppet puppet 1960 7
3 13:21 client01.puppet.com.pem
-rw-r--r-- 1 puppet puppet 1960 7
3 13:21 client02.puppet.com.pem
-rw-r--r-- 1 puppet puppet 2037 7
3 11:05 master.puppet.com.pem
此时,客户端已经完成证书的请求与签名。

4.2.2 配置实例

为了保护 Linux SSH 端口,批量修改客户端 SSH 端口,将默认端口 22 修改
9922,并实现重启工作。在 Master 端创建 SSH 模块,模块目录为 ssh,模块目
录下面有三个子目录:manifeststemplates files
manifests 里面必须要包含一个 init.pp 的文件,这是该模块的初始(入口)文件,
导入一个模块的时候,会从 init.pp 开始执行。可以把所有的代码都写到 init.pp
里面,也可以分成多个 pp 文件,init 再去包含其他文件,定义 class 类名的时候
必须是 ssh,这样才能实现调用。
files 目录是该模块的文件发布目录,Puppet 提供一个文件分发机制,类似 rsync
的模块。
templates 目录包含 erb 模型文件,这个和 file 资源的 template 属性有关(很少
用)。

1. 配置测试节点

Master 需要使用的相关配置文件如下:
节点信息:/etc/puppet/manifests/nodes/

模块信息:/etc/puppet/modules/

(1)Master 上创建需要的目录

[root@master ~]# cd /etc/puppet/
[root@master puppet]# mkdir -p modules/ssh/{manifests,templates,files}
[root@master puppet]# mkdir manifests/nodes
[root@master puppet]# mkdir modules/ssh/files/ssh
[root@master puppet]# chown -R puppet modules/
//修改权限
[root@master puppet]# ll modules/ssh //查看/etc/puppet/modules/ssh 目录下的结构
总用量 0
drwxr-xr-x 3 puppet root 17 7
3 14:18 files
drwxr-xr-x 2 puppet root 6 7
3 14:08 manifests
drwxr-xr-x 2 puppet root 6 7
3 14:08 templates

(2)创建模块配置文件 install.pp

[root@master ~]# vim /etc/puppet/modules/ssh/manifests/install.pp
//输入以下信息(首先确定客户端安装 SSH 服务)
class ssh::install{
package{ "openssh":
ensure => present,
}
}

(3)创建模块配置文件 config.pp

[root@master ~]# vim /etc/puppet/modules/ssh/manifests/config.pp
//输入以下信息配置需要同步的文件
class ssh::config{
file { "/etc/ssh/sshd_config":
//配置客户端需要同步的文件
ensure => present,
//确定客户端此文件存在
owner =>"root",
//文件所属用户
group =>"root",
//文件所属组
mode =>"0600",
//文件属性
source =>"puppet://$puppetserver/modules/ssh/ssh/sshd_config", // 从 服 务 器 端
同步文件
require => Class["ssh::install"],
//调用 install.pp 确定 ssh 已经安装
notify => Class["ssh::service"],
//如果 config.pp 发生变化通知 service.pp
}
}

(4)创建模块配置文件 service.pp

[root@master ~]# vim /etc/puppet/modules/ssh/manifests/service.pp
class ssh::service {
service {"sshd":
ensure=>running,
//确定 ssh 运行
hasstatus=>true, // Puppet 该服务支持 status 命令,即类似 service sshd status
hasrestart=>true, // Puppet 该服务支持 restart 命令,即类似 service sshd restart
enable=>true,
//服务器是否开机启动
require=>Class["ssh::config"]
//确认 config.pp 调用
}
}

(5)创建模块主配置文件 init.pp

[root@master ~]# vim /etc/puppet/modules/ssh/manifests/init.pp
class ssh{
include ssh::install,ssh::config,ssh::service //加载以上配置文件
}
此时,/etc/puppet/modules/ssh/manifests 目录下有四个文件。
[root@master ~]# ll /etc/puppet/modules/ssh/manifests/
总用量 16
-rw-r--r-- 1 root root 378 7 3 15:33 config.pp
-rw-r--r-- 1 root root 67 7 3 16:50 init.pp
-rw-r--r-- 1 root root 82 7 3 15:31 install.pp
-rw-r--r-- 1 root root 234 7 3 16:50 service.pp

(6)建立服务器端 ssh 统一维护文件

复制服务器端/etc/ssh/sshd_config 文件到模块默认路径。
[root@master ~]# cp /etc/ssh/sshd_config /etc/puppet/modules/ssh/files/ssh/
[root@master ~]# chown -R puppet /etc/puppet/modules/ssh/files/ssh/

(7)创建测试节点配置文件

创建测试节点配置文件,并加载 SSH
[root@master ~]# vim /etc/puppet/manifests/nodes/ssh.pp
node 'client01.puppet.com'{
include ssh
}
node 'client02.puppet.com'{
include ssh
}

(8)将测试节点载入 Puppet,即修改 site.pp

[root@master ~]# vim /etc/puppet/manifests/site.pp
import "nodes/ssh.pp"

(9)修改服务端维护的 sshd_config 配置文件

[root@master ~]# vim /etc/puppet/modules/ssh/files/ssh/sshd_config
Port 9922
//取消注释并修改为 9922
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::

(10)重新启动 Puppet Master 服务

[root@master ~]# systemctl restart puppetmaster

2. 客户端主动拉取

在其中一台 client01.puppet.com 客户端上,执行以下操作从服务器端主动拉取
配置。
[root@client01 ~]# puppet agent -t
......
//省略部分
+++ /tmp/puppet-file20200716-2177-zqlbd0
2020-07-3 17:11:57.327357239 +0800
@@ -15,6 +15,7 @@
# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER
#
#Port 22
+Port 9922
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
Info: Computing checksum on file /etc/ssh/sshd_config
Info: /Stage[main]/Ssh::Config/File[/etc/ssh/sshd_config]: Filebucketed /etc/ssh/sshd_config to
puppet with sum 0440a9608de01c4fa1c1dd6301b568ec
Notice:
/Stage[main]/Ssh::Config/File[/etc/ssh/sshd_config]/content:
content
changed
'{md5}0440a9608de01c4fa1c1dd6301b568ec' to '{md5}34ba2b7fa9efb61396216aad50899226'
Info: /Stage[main]/Ssh::Config/File[/etc/ssh/sshd_config]: Scheduling refresh of Class[Ssh::Service]
Info: Class[Ssh::Service]: Scheduling refresh of Service[sshd]
Notice: /Stage[main]/Ssh::Service/Service[sshd]: Triggered 'refresh' from 1 events
Info: Creating state file /var/lib/puppet/state/state.yaml
Notice: Finished catalog run in 1.20 seconds
[root@client01 ~]# cat /etc/ssh/sshd_config | grep Port
Port 9922
#GatewayPorts no
查看服务器 SSH 服务是否重启,端口是否生效。
[root@client01 ~]# netstat -tunlp | grep ssh
tcp
0
0 0.0.0.0:9922 0.0.0.0:*
LISTEN
2370/sshd
tcp6
0
0 :::9922
:::*
LISTEN
2370/sshd

3. 服务端主动推送

当大规模部署时不可能在每台客户端都采用拉取动作,而此时用服务器推送模式
反而更合理。在客户端 client02.puppet.com 上做修改。
(1)修改 puppet 配置文件,最后一行添加如下。
[root@client02 ~]# vim /etc/puppet/puppet.conf
listen = true //使 Puppet 监听 8139 端口
(2)修改验证配置文件 auth.conf 定义一些验证信息及访问权限,最后一行添加
如下。
[root@client02 ~]# vim /etc/puppet/auth.conf
allow *
//允许任何服务端推送
(3)启动 Puppet Agent 客户端。
[root@client02 ~]# systemctl start puppetagent
(4)修改客户端 client02.puppet.com 的/etc/ssh/sshd_config 文件,将 Port 9922
还原成最初始状态,然后重启 sshd 服务
查看还原后的/etc/ssh/sshd_config 的内容如下。
[root@client02 ~]# cat /etc/ssh/sshd_config | grep Port
#Port 22
#GatewayPorts no
[root@client02 ~]# netstat -tunlp| grep ssh
tcp
0
0 0.0.0.0:22
0.0.0.0:*
LISTEN 3161/sshd
tcp6
0
0 :::22
:::*
LISTEN 3161/sshd

(5)向 client02.puppet.com 节点推送配置。

[root@master ~]# puppet kick client02.puppet.com
Triggering client02.puppet.com
Getting status
status is success
client02.puppet.com finished with exit code 0
Finished

(6)校验结果

此时,在 client02.puppet.com 主机上可以查看到 SSH 端口已经被更改为 9922
[root@client02 ~]# cat /etc/ssh/sshd_config | grep Port
Port 9922
#GatewayPorts no
[root@client02 ~]# netstat -tunlp | grep sshd
tcp
0
0 0.0.0.0:9922 0.0.0.0:*
LISTEN
3371/sshd
tcp6
0
0 :::9922
:::*
LISTEN
3371/sshd

4.3 案例二分析

4.3.1 案例概述

如果有工作经验的朋友看到升级部署,第一时间会想到是将新的应用替换或覆盖
旧的应用,然后重启服务之类的。没错,这里的自动部署就是将新的应用自动覆盖旧
的应用,起到一个更新的作用,主要还是利用文件拷贝的原理。
网上可能大部分自动部署的案例是将 SVN Puppet Master 整合在一台服务器
上。如果 SVN 服务器里面的代码有更新,Puppet Agent 就会根据自身设置拉取更新
文件完成全自动部署。这样做唯一的缺点就是如果出现问题,不能很好的控制。例如:
由于开发人员误操作导致一个错误的文件已提交到 SVN 服务器上,那么 Agent 节点
也会更新成错误的文件,而 Web 站点将会出现故障。所以将 SVN 服务器、Puppet
Master 服务器、发布服务器建议全部单独分开,只要保证发布服务器上的代码不会更
新错误的文件,Web 站点也就不会自动更新。因此,就不能用 Puppet Master 作为文
件服务器,而是以发布服务器作为文件服务器,所以需要用到 Puppet rsync 模块。

4.3.2 案例前置知识点

自动部署工作流程如图 4.3 所示。
4.3 自动部署工作流程
开发人员手工提交更新代码到 SVN 服务器上。
开发人员使用系统账号登录到发布服务器上,手工执行与发版相对应的项目脚本。
也就是从 SVN 服务器上检出要更新的代码到发布机上。
待脚本执行完后,Web 测试环境的应用会根据自身设置的时间自动更新或者更新
后执行一些其它动作。这里暂定五分钟。
开发人员和测试人员进行相关测试。
如果测试环境通过测试,需要发布正式环境的话,请开发人员邮件或者电话通知
运维人员要发版的项目。
同样运维人员也是手工执行与发版相对应的项目脚本(正式环境发布脚本),发
布完成后五分钟左右通知开发人员发布结束。

4.3.3 案例环境

1. 本案例实验环境

本案例主要演示项目版本自动部署,这里使用五台服务器,五台服务器均采用
CentOS 7.3 系统版本,要求能上互联网,Selinux 和防火墙均已关闭。服务器具体信
息如表 4-2 所示。
4-2 服务器具体配置信息
角色主机名IP 地址用途
mastermaster.puppet.com192.168.0.111控制端
clientweb.puppet.com192.168.0.112正式节点
clientweb-test.puppet.com192.168.0.113测试节点
releaserelease.puppet.com192.168.0.114时间同步,发布机
svnsvn.puppet.com192.168.0.115版本控制

确保发布服务器到另外四台服务器网络都是相通的。同时确保所有服务器的时间

都同步。本案例的自动部署网络环境比较适合于公司内部机房有一条 SDH 专线连到
IDC 机房,而不是通过互联网去部署,因为这样相当于在局域网内执行动作,速度和
安全性都是比较可靠的。SVN 服务器、发布服务器、Puppet Master 都在公司内部,
Web 正式节点和 Web 测试节点都在 IDC 机房中。所以说自动部署也在很大程度上依
赖网络环境。

2. 案例需求

使用 Puppet 进行项目版本发布。

3. 案例实现思路

1)准备工作;
2)安装 Puppet 软件;
3)安装配置 SVN 服务器;
4)配置 Puppet 服务端和客户端;
5Puppet 部署发布服务器;
6)发布测试和正式应用。
4.4 案例二实施
1. 准备工作
(1)添加域名解析
需要修改 Puppet Master、发布服务器、Web 正式节点、Web 测试节点、SVN
服务器的 hosts 文件,因为 Puppet 都是基于域名的方式来管理节点。如果 IDC 机房
内部有 DNS 管理更好,因为以后更多的项目都会自动部署。以 master.puppet.com主机为例,五台服务器都增加如下解析:
[root@master ~]# cat << EOF >> /etc/hosts
192.168.0.111 master.puppet.com
192.168.0.112 web.puppet.com
192.168.0.113 web-test.puppet.com
192.168.0.114 ntp.puppet.com release.puppet.com
192.168.0.115 svn.puppet.com
EOF
(2)同步时间
五台服务器都需要进行时间同步操作,下面以 master.puppet.com 主机为例进行
演示。
[root@master ~]# ntpdate ntp.puppet.com
14 Jun 16:02:59 ntpdate[19748]: adjust time server 192.168.0.114 offset 0.001015 sec
2. 安装 Puppet
Puppet Master、发布服务器、Web 正式节点和 Web 测试节点都需要安装
Puppet 源。Puppet Master 需要安装 puppet-server 包,而发布服务器、Web 正式节
点和 Web 测试节点都被看作是 Puppet 的被管理节点,即通常所说的 Agent 端。在
场景一中,Puppet Master 节点已经安装了 puppet-server 包,可执行以下命令确认。
[root@master ~]# systemctl status puppetmaster
● puppetmaster.service - Puppet master
Loaded: loaded (/usr/lib/systemd/system/puppetmaster.service; enabled; vendor preset:
disabled)
Active: active (running) since 2020-07-19 19:00:15 CST; 42min ago
Main PID: 12300 (puppet)
CGroup: /system.slice/puppetmaster.service
└─12300 /usr/bin/ruby /usr/bin/puppet master --no-daemonize
......
//省略部分内容
[root@master ~]# netstat -antpu |grep 8140
tcp
0
0 0.0.0.0:8140
0.0.0.0:*
LISTEN
18686/ruby
Web 正式节点和 Web 测试节点在场景一中都已经安装了 Puppet,下面只是演示
在发布机上进行安装 Puppet。进行安装 Puppet 操作之前,需要提前上传下载好的
puppetlabs 源的 rpm 包。
[root@release ~]# rpm -ivh puppetlabs-release-7-12.noarch.rpm
[root@release ~]# yum install -y puppet
3. 安装配置 SVN 服务器
svn.puppet.com 服务器上,安装并配置 SVN 服务。
[root@svn ~]# yum install -y subversion
//svn.puppet.com 服务器上安装 SVN 服务
[root@svn ~]# mkdir -p /var/svn/html
//创建目录
[root@svn ~]# svnadmin create /var/svn/html/
//创建版本库
[root@svn ~]# ls /var/svn/html/
//查看生成文件
conf db format hooks locks README.txt
[root@svn ~]# vim /var/svn/html/conf/svnserve.conf
//修改 svn 配置文件
anon-access = read
//匿名用户可读
auth-access = write
//授权用户可写
password-db = /var/svn/html/conf/passwd
//指定账号文件
authz-db = /var/svn/html/conf/authz
//指定权限文件
[root@svn ~]# vim /var/svn/html/conf/passwd
//设置账号密码
[users]
alpha = alphapasswd
sysadmin = sysadminpasswd
[root@svn ~]# vim /var/svn/html/conf/authz
//设置权限
[/]
sysadmin = r
alpha = rw
[web]
sysadmin = r
alpha = rw
[root@svn ~]# svnserve -d -r /var/svn/html
//启动版本库
创建测试目录并测试。
[root@svn ~]# cd /var/svn/html/
[root@svn html]# mkdir web
[root@svn html]# svn import web file:///var/svn/html/web -m "init svn"
提交后的版本为 1
4. 配置 Puppet Agent
因为 Puppet Master 管理客户端 Agent 是基于 SSL 方式通过证书通信,所以需
要在所有的 Agent 角色上,也就是在发布服务器、Web 正式节点、Web 测试节点上
修改 Puppet 的主配置文件/etc/puppet/puppet.conf,在[main]字段中指定 Puppet
务端地址。因为场景一和场景二中某些主机名已经发生改变,所以都需要重新认证。
下面以发布机上为例进行演示。
[root@release ~]# vim /etc/puppet/puppet.conf
server = master.puppet.com
// Puppet Master 的地址
然后,在所有的 Agent 角色上分别执行如下命令,向 Master 发起注册请求。
[root@release ~]# puppet agent --server=master.puppet.com --verbose --no-daemonize
Master 进行查看申请注册的客户端,执行如下命令。
[root@master ~]# puppet cert --list
"release.puppet.com"
(SHA256)
12:A3:04:91:1D:2D:FE:83:D7:E7:F2:C7:CC:B6:CC:D4:92:B4:E8:35:42:D6:35:B6:E8:CB:71:D9:F5:
D4:69:00
"web-test.puppet.com"
(SHA256)
F6:71:F4:D1:75:9A:8A:C2:CB:DD:50:56:F7:6E:2A:1E:5C:7D:71:85:DC:D4:39:AF:69:44:D3:AE:EE:
46:2F:B1
"web.puppet.com"
(SHA256)
E2:A3:55:17:43:61:AA:CC:53:24:72:2A:23:2B:33:9A:A9:0C:E1:6A:46:91:FB:B1:C1:55:06:C5:77:10:
59:B2
Puppet Master 执行如下命令完成注册。
[root@master ~]# puppet cert sign release.puppet.com
//单个客户端
Notice: Signed certificate request for release.puppet.com
Notice:
Removing
file
Puppet::SSL::CertificateRequest
release.puppet.com
at
'/var/lib/puppet/ssl/ca/requests/release.puppet.com.pem'
[root@master ~]# puppet cert sign --all
//所有客户端
Notice: Signed certificate request for web.puppet.com
Notice:
Removing
file
Puppet::SSL::CertificateRequest
web.puppet.com
at
'/var/lib/puppet/ssl/ca/requests/web.puppet.com.pem'
Notice: Signed certificate request for web-test.puppet.com
Notice:
Removing
file
Puppet::SSL::CertificateRequest
web-test.puppet.com
at
'/var/lib/puppet/ssl/ca/requests/web-test.puppet.com.pem'
5. 使用 Puppet 部署发布服务器
(1)下载 concat 和 rsync 模块
在发布服务器和 Puppet Master 上需要下载安装 concat rsync 模块。如果发布
服务器上没有 concat rsync 模块,那么之后发布服务器上生成的 rsyncd.conf 文件
的 内 容 就 会 是 空 的 。 Puppet 对 应 concat 模 块 的 下 载 位 置 在 GitHub 位 置
https://github.com/onyxpoint/pupmod-concat,对应 rsync 模块的下载位置在 GitHub
位置 https://github.com/onyxpoint/pupmod-rsync
这里是使用 git。如果服务器没有安装,可以先使用 yum -y install git 安装。如果
不想安装 git,也可以下载 zip 压缩包,解压到相应目录。
在发布服务器、Puppet Master 上执行如下命令。
[root@release ~]# yum install -y git
[root@release ~]# cd /etc/puppet/modules/
[root@release modules]# git clone https://github.com/onyxpoint/pupmod-concat && mv
pupmod-concat concat
正克隆到 'pupmod-concat'...remote: Enumerating objects: 116, done.
remote: Total 116 (delta 0), reused 0 (delta 0), pack-reused 116
接收对象中: 100% (116/116), 48.07 KiB | 47.00 KiB/s, done.
处理 delta : 100% (26/26), done.
[root@release modules]# git clone https://github.com/onyxpoint/pupmod-rsync && mv
pupmod-rsync rsync
正克隆到 'pupmod-rsync'...
remote: Enumerating objects: 36, done.
remote: Total 36 (delta 0), reused 0 (delta 0), pack-reused 36
Unpacking objects: 100% (36/36), done.
[root@release modules]# ll
总用量 0
drwxr-xr-x 5 root root 72 7 3 20:26 concat
drwxr-xr-x 8 root root 118 7 3 20:26 rsync
(2)配置 Puppet Master
Puppet Master 开始创建管理 Agent 节点目录及文件,方便以后管理。
[root@master ~]# mkdir -p /etc/puppet/manifests/nodes
[root@master ~]# vim /etc/puppet/manifests/nodes/release.puppet.com.pp
class rsync::client inherits rsync {
}
node 'release.puppet.com' {
include 'rsync::server'
rsync::server::global { 'global':
address => '192.168.0.114'
}
rsync::server::section { 'web':
comment => 'This is formal file path',
path => '/var/www/html/web',
hosts_allow => '192.168.0.112'
}
rsync::server::section { 'web_test':
comment => 'This is test file path',
path => '/var/www/html/web_test',
hosts_allow => '192.168.0.113'
}
}
(3)创建 site.pp 配置文件
site.pp 配置文件中定义 Puppet 相关的变量和默认配置,site.pp Puppet
最先读取的文件。
[root@master ~]# vim /etc/puppet/manifests/site.pp
import "nodes/release.puppet.com.pp"
(4)自动配置发布服务器
[root@release ~]# puppet agent --server=master.puppet.com --test -v
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for release.puppet.com
Info: /Stage[main]/Rsync/Tidy[/etc/rsync]: File does not exist
Info: Applying configuration version '1528969467'
Notice: /Stage[main]/Rsync/File[/etc/rsync]/ensure: created
Notice:
//省略部分
Notice: /Stage[main]/Rsync::Server/Service[rsync]/ensure: ensure changed 'stopped' to 'running'
Info: /Stage[main]/Rsync::Server/Service[rsync]: Unscheduling refresh on Service[rsync]
Notice: Finished catalog run in 8.25 seconds
查看发布服务器的/etc 目录,发现已经自动生成 rsyncd.conf 文件,但是 rsync
服务是未启动的。自动生成的/etc/rsyncd.conf 文件内容如下。
[root@release ~]# cat /etc/rsyncd.conf
pid file = /var/run/rsyncd.pid
syslog facility = daemon
port = 873
address = 192.168.0.114
[web]
comment = This is formal file path
path = /var/www/html/web
use chroot = false
max connections = 0
max verbosity = 1
lock file = /var/run/rsyncd.lock
read only = true
write only = false
list = false
uid = root
gid = root
outgoing chmod = o-w
ignore nonreadable = true
transfer logging = true
log format = "%o %h [%a] %m (%u) %f %l"
dont compress = *.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz *.rar *.jar *.pdf *.sar *.war
hosts allow = 192.168.0.112
hosts deny = *
[web_test]
comment = This is test file path
path = /var/www/html/web_test
use chroot = false
max connections = 0
max verbosity = 1
lock file = /var/run/rsyncd.lock
read only = true
write only = false
list = false
uid = root
gid = root
outgoing chmod = o-w
ignore nonreadable = true
transfer logging = true
log format = "%o %h [%a] %m (%u) %f %l"
dont compress = *.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz *.rar *.jar *.pdf *.sar *.war
hosts allow = 192.168.0.113
hosts deny = *
(5)启动 rsync 服务
在发布服务器上手动启动 rsync 服务。
[root@release ~]# rsync --daemon
查看 873 端口是否开启。如果发布机上开启防火墙,记得打开 873 端口。
[root@release ~]# netstat -an | grep 873
tcp
0
0 192.168.0.114:873
0.0.0.0:*
LISTEN
如果希望下次发布服务器能自动启动 rsync 服务,那么需要修改 Puppet Master
rsync 模块文件,将/etc/puppet/modules/rsync/manifests/server.pp 文件中的如下
行注释掉。
stop => "/bin/kill `cat \\`grep \"pid file\" /etc/rsyncd.conf | cut -f4 -d' '\\``",
新增如下所示:
stop => "/bin/kill `ps -ef | grep rsync | grep -v grep | awk '{print $2}'`",
6. 版本发布
在上面搭建 SVN 服务器的时候只设置了一个版本库,但是目录里面实际是空的,
为了模拟真实性,上传一个本地文件到 svn 版本库,然后通过发布脚本将这个文件发
布到测试站点。
(1)从 SVN 服务器检出项目,检出的时候需要输入 SVN 服务器密码,然后输入
svn 用户和密码。
[root@release ~]# svn co svn://svn.puppet.com/web
[root@release ~]# cd web
从本地拷贝一个文件到 SVN 版本库。
[root@release web]# cp /root/anaconda-ks.cfg .
添加文件到 SVN 版本库,删除文件是使用 delete 参数。
[root@release web]# svn add anaconda-ks.cfg
A
anaconda-ks.cfg
提交到版本库,ci commit 的简写。
[root@release web]# svn ci -m "add file"
正在增加
anaconda-ks.cfg
传输文件数据.
提交后的版本为 2
(2)编写 SVN 发布测试站点脚本
[root@release ~]# vim webtest.sh
#web 测试环境版本发布工具#!/bin/bash
#定义路径
path=$(cd $(dirname "$0");pwd);
svnRoot="svn://svn.puppet.com/web";
svndir="/var/svn/html/web_test";
webdir="/var/www/html/web_test";
choose="no yes"
echo "请确认要发布的是 web 项目测试环境";
select comfirm in $choose
do
if [ "${comfirm}" != "yes" ];then
echo "发布程序结束"
exit 0;
fi
break;
done;
echo "请确认 SVN 地址(默认 no):${svnRoot}";
select comfirm in $choose
do
if [ "${comfirm}" != "yes" ];then
echo "发布程序结束"
exit 0;
fi
break;
done;
#开始检出程序代码
svn co ${svnRoot}
${svndir};
rsync -acvz --exclude=".svn/" --delete --delete-after ${svndir}/ ${webdir}
当然脚本里面还可以增加其它的预设动作,根据不同的业务逻辑进行修改。
执行脚本之前需要在发布服务器上创建需要的目录。
[root@release ~]# mkdir -p /var/svn/html/web_test
[root@release ~]# mkdir -p /var/www/html/web_test
(3)配置 Web 测试站点客户端
Puppet Master 上定义客户端模板文件。因为下载的 rsync 模块不带--delete
参数,但是在实际环境中完全同步代码的时候需要用到这个参数。
[root@master ~]# mkdir /etc/puppet/modules/rsync/manifests/client
[root@master ~]# vim /etc/puppet/modules/rsync/manifests/client/host.pp
//添加如下内容
define rsync::client::host ($title,$rsyserver,$source,$target){
exec{"$title":
path => "/usr/bin:",
command => "rsync -acvz --delete $rsyserver::$source $target"
}
}
上述参数含义:
title:定义的一个主题,可以任意定义。
rsyserver:是 rsync server IP
source:是 rsync server 上定义的目录。
target:是网站测试节点上放置的目录。
(4)创建测试站点文件
[root@master ~]# vim /etc/puppet/manifests/nodes/web-test.puppet.com.pp
node 'web-test.puppet.com' {
include 'rsync::client'
rsync::client::host {"web 项目测试环境":
title => 'web 项目测试环境',
source =>'web_test',
rsyserver => 'release.puppet.com',
target =>'/var/www/html/web_test'
}
}
上述内容很少,因为完全就是调用 rsync 命令复制文件。当然,里面也可以增加
同 步 完 后 的 一 些 预 设 动 作 , 比 如 exec 执 行 外 部 脚 本 之 类 的 。 最 后 , 需 要 将
web-test.puppet.com 文件也导入到 site.pp 文件里面。
[root@master
~]#
echo
"import
'nodes/web-test.puppet.com.pp'
">>
/etc/puppet/manifests/site.pp
(5)手动测试
手动运行上面创建的发布脚本 webtest.sh
[root@release ~]# sh webtest.sh
请确认要发布的是 web 项目测试环境
1) no
2) yes
#? 2
请确认 SVN 地址(默认 no):svn://svn.puppet.com/web
1) no
2) yes
#? 2
A
/var/svn/html/web_test/anaconda-ks.cfg
取出版本 2
Building file list ... done
anaconda-ks.cfg
sent 785 bytes received 34 bytes 1,638.00 bytes/sec
total size is 1,260 speedup is 1.54
查看文件是否已经检出到发布机。
[root@release ~]# ll /var/svn/html/web_test/
总用量 4
-rw-r--r-- 1 root root 1261 7 3 21:25 anaconda-ks.cfg
Web 项目测试站点上创建同步目录,然后执行如下命令确认发布服务器上的
更新文件是否被同步到 Web 项目测试站点。
[root@web-test ~]# mkdir -p /var/www/html/web_test
[root@web-test ~]# puppet agent --server master.puppet.com --test --debug
//省略部分
Notice: /Stage[main]/Rsync/Tidy[/etc/rsync]: Tidying File[/etc/rsync]
Info: Applying configuration version ‘1529027298’
Debug: Exec[web 项 目 测 试 环 境 ](provider=posix): Executing ‘rsync -acvz —delete
192.168.0.114::web_test /var/www/html/web_test’
Debug: Executing ‘rsync -acvz —delete 192.168.0.114::web_test /var/www/html/web_test’
Notice: /Stage[main]/Main/Node[web-test.puppet.com]/Rsync::Client::Host[web 项 目 测 试 环
]/Exec[web 项目测试环境]/returns: executed successfully
//省略部分
Web 测试节点查看文件是否被同步。
[root@web-test ~]# ll /var/www/html/web_test/
总用量 4
-rw-r--r-- 1 root root 1261 7 3 21:25 anaconda-ks.cfg
再测试一下上面添加的 host.pp 是否可用,首先从 svn 删除 anaconda-ks.cfg
然后重新上传一个文件进行测试。
[root@release ~]# cd web
[root@release web]# svn delete anaconda-ks.cfg
D
anaconda-ks.cfg
[root@release web]# svn ci -m "delete file"
正在删除
anaconda-ks.cfg
提交后的版本为 3
[root@release web]# cp /root/webtest.sh .
[root@release web]# svn add webtest.sh
A
webtest.sh
[root@release web]# svn ci -m "add new file"
正在增加
webtest.sh
传输文件数据.
提交后的版本为 4
运行发布脚本
[root@release ~]# sh webtest.sh
Web 测试节点手动同步。
[root@web-test ~]# puppet agent --server master.puppet.com --test
Notice: Ignoring —listen on onetime run
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for web-test.puppet.com
Notice: /Stage[main]/Rsync/Tidy[/etc/rsync]: Tidying File[/etc/rsync]
Info: Applying configuration version ‘1529027298’
Notice: /Stage[main]/Main/Node[web-test.puppet.com]/Rsync::Client::Host[web 项 目 测 试 环
]/Exec[web 项目测试环境]/returns: executed successfully
Notice: Finished catalog run in 1.53 seconds
Web 测试节点查看,发现文件旧文件已经删除,新文件已经同步。
[root@web-test ~]# ll /var/www/html/web_test/
总用量 4
-rw-r--r-- 1 root root 784 7 3 21:31 webtest.sh
(6)设置正式节点自动部署
上述都是手动执行拉取动作,而本案例的目的是自动部署,所以需要配置正式节
点的 Agent 自动更新应用。
① 修改 Agent 自动更新
在正式环境上的 Agent 客户端的/etc/puppet/puppet.conf 配置文件中的[agent]
段中增加如下内容。
[root@web ~]# vim /etc/puppet/puppet.conf
listen = true
runinterval = 300s
//表示 5 分钟自动更新
[root@web ~]# systemctl restart puppetagent
至于发布服务器上为了防止 rsync 进行消失,也可以采用一小时自动拉取一次。
具体时间根据需求而定。
② 编写正式发布脚本,其实原理就是把发布机上的/var/www/html/web_test 目录
下的文件拷贝到/var/www/html/web 目录下。
[root@release ~]# vim web.sh
#!/bin/bash
#设置根目录
SOURCE_ROOT='/var/www/html';
SHELL_ROOT=$(cd $(dirname "$0"); pwd);
#设置源码目录
SOURCE_WEB="${SOURCE_ROOT}/web";
SOURCE_WEB_TEST="${SOURCE_ROOT}/web_test";
choose="no yes"echo "请确认要发布的是 web 项目正式环境?(该脚本只能由运维人员执行)";
select comfirm in $choose
do
if [ "${comfirm}" != "yes" ]; then
echo "发布程序结束";
exit 0;
fi
break;
done;
echo "请确认是否同步正式环境?请务必确认目录正确性!";
select COMFIRM in '' ''
do
if [ "${COMFIRM}" == "" ]; then
echo '同步源码目录';
rsync -avr --delete-after ${SOURCE_WEB_TEST}/ ${SOURCE_WEB};
fi
break;
done;
echo 'web 项目正式环境发布完成,请通知相关开发和测试人员五分钟后进行测试!'
手动运行发布正式节点脚本。
[root@release ~]# sh web.sh
请确认要发布的是 web 项目正式环境?(该脚本只能由运维人员执行)
1) no
2) yes
#? 2
请确认是否同步正式环境?请务必确认目录正确性!
1)
2)
#? 2
同步源码目录
building file list ... done
created directory /var/www/html/web
./
webtest.sh
sent 939 bytes received 96 bytes 2,070.00 bytes/sec
total size is 769 speedup is 0.74
web 项目正式环境发布完成,请通知相关开发和测试人员五分钟后进行测试!
查看发布机的正式目录文件是否同步。
[root@release ~]# ll /var/www/html/web/
总用量 4
-rw-r--r-- 1 root root 769 6 15 10:37 webtest.sh
③ 创建正式节点文件
[root@master ~]# vim /etc/puppet/manifests/nodes/web.puppet.com.pp
node 'web.puppet.com' {
include 'rsync::client'
rsync::client::host {"web 项目正式环境":
title => 'web 项目正式环境',
source =>'web',
rsyserver => 'release.puppet.com',
target =>'/var/www/html/web'
}
}
同样还需要将 web.puppet.com.pp 文件 import site.pp 文件里面。
[root@master ~]# echo "import 'nodes/web.puppet.com.pp'">>/etc/puppet/manifests/site.pp
重启 Puppet Master 服务。
[root@master ~]# systemctl restart puppetmaster
在正式节点创建同步目录。
[root@web ~]# mkdir -p /var/www/html/web
接下来,就是耐心得等待 5 分钟后进行查看文件已经同步。
[root@web ~]# ll /var/www/html/web/
总用量 0
[root@web ~]# ll /var/www/html/web/
总用量 4
-rw-r--r-- 1 root root 784 7 3 21:31 webtest.sh
至此,项目就自动化部署完成了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2139481.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

逻辑漏洞-其二(登录验证码安全)

2.登录验证码安全 验证码漏洞检测流程 2.1 图形验证码 无效验证 2.1.1 验证码可爆破 验证码可爆破&#xff0c;即验证码过于简单&#xff0c;例如验证码中字符数量过少&#xff0c;比如只有四位组成&#xff0c;且只包含 0-9 的数字还没有干扰点 &#xff0c;亦或者 验证码可以…

Python---爬虫

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 Python爬虫是一种通过自动化程序爬取互联网上的信息的技术。爬虫可以自动访问网页并提取所需的数据&#xff0c;比如网站的文本、图片、视频等。Python是一种简单易学的编程语言&#xff…

建筑裂缝检测图像ai模型训练数据集

共52w例图像的建筑裂缝检测图像ai模型训练数据集 20 地上设施&#xff08;公路桥梁、铁路桥梁、水坝&#xff08;墙&#xff09;、挡土墙&#xff09;和地下 SOC 设施&#xff08;公路/铁路隧道、地铁、水隧道&#xff09;&#xff1b;韩国40 个市、县、区 SOC 设施的数据&…

读构建可扩展分布式系统:方法与实践05分布式缓存

1. 分布式缓存 1.1. 缓存存在于应用程序的许多地方 1.1.1. 行应用程序的CPU具有高速多级硬件缓存&#xff0c;可以减少相对较慢的主内存访问 1.1.2. 数据库引擎可以利用主内存来缓存数据存储的内容&#xff0c;这样在许多情况下查询就可以不用访问速度相对较慢的磁盘 1.2. …

给树莓派添加 SSD1306 OLED 小屏幕

树莓派被作为一个小服务器使用的时候&#xff0c;通常都不需要接一台专用显示器&#xff0c;而是通过 ssh 远程登录。当环境中有多个设备使用远程登录的时候&#xff0c;就容易不记得相应设备的 IP 地址等信息&#xff1b;有时候只是需要了解设备的一些信息&#xff0c;例如 CP…

【GPU版】Windows下PyTorch入门深度学习环境安装与配置

如果电脑有NVIDIA GPU显卡&#xff0c;看【GPU版本】&#xff1b;否则&#xff0c;看【CPU版本】 聊聊PyTorch和Tensorflow 它们都是python的库/包 pip3是给python3使用的&#xff0c;由于现在用的python基本上都是3以上版本&#xff0c;所以pip和pip3没有区别 聊聊Anacond…

✔3290. 最高乘法得分

代码实现&#xff1a; 动态规划 /*从 b 中选一个长为 4 的子序列定义 dfs(i,j) 表示 从 b[0] 到 b[i] 中选出 j1 个数&#xff0c;去和 a[0] 到 a[j] 算一个点积的最大值考虑 b[i] 选或不选不选 dfs(i-1,j)选 dfs(i-1,j-1) a[j] * b[i]dfs(i,j) max(dfs(i-1),j), dfs(i-1,j-1…

FreeRTOS实战指南 — 2 移植 FreeRTOS 到 STM32F429

目录 1 准备裸机工程文件 2 创建FreeRTOS文件夹结构 3 修改Keil工程文件 3.1 添加工程文件 3.2 指定 FreeRTOS 头文件的路径 4 移植FreeRTOSConfig.h配置文件 4.1 移植FreeRTOSConfig.h 4.2 详解FreeRTOSConfig.h 4.3 修改FreeRTOSConfig.h 5 修改main.c 1 准备裸机工…

Java | Leetcode Java题解之第409题最长回文串

题目&#xff1a; 题解&#xff1a; class Solution {public int longestPalindrome(String s) {int[] count new int[128];int length s.length();for (int i 0; i < length; i) {char c s.charAt(i);count[c];}int ans 0;for (int v: count) {ans v / 2 * 2;if (v …

开源 AI 智能名片小程序:开启内容营销新境界

摘要&#xff1a;本文深入探讨了在当今数字化时代&#xff0c;内容营销的重要性以及如何实现让用户主动找你的最佳效果。通过引入开源 AI 智能名片小程序这一创新工具&#xff0c;阐述了其在明确目标用户群体、迎合用户需求痛点和打造风格特色方面的独特优势&#xff0c;为企业…

VMware ESXi 7.0U3q macOS Unlocker 集成驱动版更新 OEM BIOS 2.7 支持 Windows Server 2025

VMware ESXi 7.0U3q macOS Unlocker 集成驱动版更新 OEM BIOS 2.7 支持 Windows Server 2025 VMware ESXi 7.0U3q macOS Unlocker & OEM BIOS 2.7 集成网卡驱动和 NVMe 驱动 (集成驱动版) ESXi 7.0U3 标准版集成 Intel 网卡、Realtek USB 网卡 和 NVMe 驱动 请访问原文链…

虚幻引擎 | (类恐鬼症)玩家和NPC语音聊天(下)

上下文Conversation Array 要让GPT记住上下文&#xff0c;实现GPT4里的连续对话功能&#xff0c;需要把以下内容存入conversation array中去。 NPC background storyuser input promptNPC anwser open AI API的JsonObject JSONObject是一种数据结构&#xff0c;可以理解为JSO…

【最佳实践】配置类封装-Async异步注解以及自定义线程池

效果是&#xff1a;能点进去看到自定义的线程池&#xff0c;代表指定自定义的线程池成功&#xff01; 自定义Async线程池 自定义线程池 import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.…

Android14音频进阶之如何集成音效(八十五)

简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+…

Parallels Desktop 20 版本功能汇总,附最新PD虚拟机下载链接

Parallels Desktop 20 for Mac 已正式发布&#xff01;作为目前 Mac 上极为好用强大的「虚拟机」软件&#xff0c;它完美支持最新的 macOS Sequoia 15 系统和 Windows 11 24H2&#xff0c;这次还引入了许多诸如 AI 等令人期待的全新功能和改进。为普通用户、开发者、设计师都带…

第十一章 【后端】商品分类管理微服务(11.2)——Lombok

11.2 Lombok 官网:https://projectlombok.org/ 较新版本的 idea 已默认安装 lombok 插件 Lombok 工具提供一系列的注解,使用这些注解可以不用定义 getter、setter、equals、constructor 等,可以消除 java 代码的臃肿,编译时它会在字节码文件中自动生成这些通用的方法,简…

【算法专题】穷举vs暴搜vs深搜vs回溯vs剪枝

二叉树剪枝 LCR 047. 二叉树剪枝 - 力扣&#xff08;LeetCode&#xff09; 本题要求我们将全部为0的二叉树去掉&#xff0c;也就是剪枝&#xff0c;当我们举一个具体的例子进行模拟时&#xff0c;会发现&#xff0c;只关注于对其中一个子树的根节点进行剪枝&#xff0c;由于我…

企业竞争文化数据,词频分析(2007-2022年)

企业竞争文化的核心价值观包括&#xff1a; 追求卓越&#xff1a;鼓励员工不断超越自我&#xff0c;提升个人和团队的绩效。领导力&#xff1a;强调领导者在塑造竞争文化中的重要作用&#xff0c;引领团队向更高目标前进。创新思维&#xff1a;倡导员工面对挑战时采取创新方法…

25届计算机专业选题推荐-基于微信小程序的校园快递驿站代收管理系统

&#x1f496;&#x1f525;作者主页&#xff1a;毕设木哥 精彩专栏推荐订阅&#xff1a;在 下方专栏&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; 实战项目 文章目录 实战项目 一、基于微信小程序的校园快递驿…

Golang | Leetcode Golang题解之第406题根据身高重建队列

题目&#xff1a; 题解&#xff1a; func reconstructQueue(people [][]int) (ans [][]int) {sort.Slice(people, func(i, j int) bool {a, b : people[i], people[j]return a[0] > b[0] || a[0] b[0] && a[1] < b[1]})for _, person : range people {idx : pe…