ansible-playbook 进阶 接上一章内容

article/2025/7/15 17:08:21

1.异常中断

做法1:强制正常

编写 nginx playbook 文件 01-zuofa .yml
- hosts : web
 remote_user : root
 tasks :
- name : create new user
     user : name = nginx-test system = yes uid = 82 shell =/ sbin / nologin
- name : test new user
     shell : getend passwd | grep nginx-test || /bin/true
.. .
注: test new user 任务的 shell 后面添加 || / bin / true
做法2:忽略错误
编写 nginx playbook 文件 02-zuofa .yml
- hosts : web
 remote_user : root
 tasks :
- name : create new user
     user : name = nginx-test system = yes uid = 82 shell =/ sbin / nologin
- name : test new user
     shell : getend passwd | grep nginx-test
     ignore errors: true
.. .
注: test new user 任务的 shell下面 添加   ignore errors: true

2. 任务依赖

对于这种内容发生更改,服务应该重启的场景,在 playbook 中我们称之为 " 关系依赖 " playbook 对于这种特殊的关系有两个语法可以满足解决方法的需求:
举例说明:
顺序依赖
安装并启动 Nginx 服务。先执行安装 Nginx 的任务,安装完成后再执行启动 Nginx 的任务。
“Start Nginx” 任务依赖于 “Install Nginx” 任务,只有 Nginx 成功安装后,才尝试启动它。如果不按此顺序,在 Nginx 未安装时就尝试启动,必然会失败。

条件依赖
一个任务是否执行取决于另一个任务的执行结果(成功或失败)。可以通过 when 语句结合任务执行结果的变量来实现。
数据依赖
一个任务需要使用另一个任务的输出数据作为输入。通常通过 register 关键字将一个任务的输出注册到变量,然后在其他任务中引用该变量。

为了解决这个问题,我们需要有⼀种⽅式能解决我们这种存在依赖关系的任务场景。

notify : 监控我们指定的动作涉及的内容是否发生了变化
handlers :接收到变化动作后,我们自动执行的其他操作命令

注:由于notify涉及到的动作是由handlers创建的,在实践过程先写handlers,再在notify中调用

1. 解决依赖[M]   增加了handler下面的内容
- hosts: webremote_user: roottasks:- name: create new useruser:name: nginx-testsystem: yesuid: 82shell: /sbin/nologin- name: test new usershell: getend passwd | grep nginx-testignore_errors: True- name: create web rootfile:name: /data/webserver/htmlowner: nginx-teststate: directory- name: touch web indexshell: echo '<h1>welcome to ansible</h1>' > /data/webserver/html/index.html- name: install packageapt:name: nginxstate: present- name: copy configcopy:src: nginx.confdest: /etc/nginx/nginx.conf- name: copy subconfigcopy:src: nginx-define.confdest: /etc/nginx/conf.dnotify: restart nginx- name: start serviceservice:name: nginxstate: startedenabled: yes  # 为了掩饰效果,不要改成restarthandlers:- name: restart nginxservice:name: nginxstate: restarted

2. 触发多任务   

文件名:05-nginx.yml  

我们刚才基于 handler notify 的实践实现的是一个 notify 触发一个 handler 的效果,但是生产中肯定会出现一个 notify 触发多个 handler 的效果。
在上面的文件最下面增加了下面的内容
- name : check nginx
     shell : netstat - tnulp | grep nginx > / tmp / nginx.test
sed - i 's/10089/10090/g' nginx-define.conf  更改端口
ansible-playbook 05 - nginx.yml    #启动任务
ansible web -m shell -a "netstat -tnulp | grep nginx"   检查效果

3. 标签  

一个 playbook 中有数十个任务,而我们只需要执行其中的一个  这就是标签存在的意义
ansible-playbook --list-tags 文件名   #查看标签
给任务添加标签  
给playbook中的拷贝配置⽂件的⼦任务添加标签  假设修改后的文件是06-nginx.yml
sed - i 's/10090/10091/g' nginx-define.conf    修改启动端口
ansible-playbook -- tags copyconfig 06-nginx.yml     重新执⾏ playbook 效果
结果显示:只有指定的 tag 标签的任务被执行了
ansible web -m shell -a "netstat -tnulp | grep nginx"    检查效果
多标签案例实践
清除环境
ansible web - m service - a "name=nginx state=stopped"
ansible web - m yum  - a "name=nginx,nginx-common state=absent"
ansible web - m file - a "path=/data/webserver state=absent"
ansible web - m user - a "name=nginx-test state=absent"
修改文件  假设文件名为07-nginx.yml
- hosts: webtags: host-tagsremote_user: roottasks:- name: create new useruser:name: nginx-testsystem: yesuid: 82shell: /sbin/nologintags: installtask- name: test new usershell: getend passwd | grep nginx-testignore_errors: Truetags: installtask- name: create web rootfile:name: /data/webserver/htmlowner: nginx-teststate: directorytags: installtask- name: touch web indexshell: echo '<h1>welcome to ansible</h1>' > /data/webserver/html/index.htmltags: installtask- name: install packageyum:name: nginxstate: presenttags: installtask- name: copy configcopy:src: nginx.confdest: /etc/nginx/nginx.conftags: installtask- name: copy subconfigcopy:src: nginx-define.confdest: /etc/nginx/conf.dnotify:- restart nginx- check nginxtags:- changetask- installtask- name: start serviceservice:name: nginxstate: startedenabled: yestags: installtaskhandlers:- name: restart nginxservice:name: nginxstate: restarted- name: check nginxshell: netstat -tnulp | grep nginx > /tmp/nginx.test
sed - i 's/10091/10086/g' nginx-define.conf     #更改端口
ansible-playbook --tags installtask 07-nginx.yml   #重新启动执行playbook效果
sed - i 's/10086/10096/g' nginx-define.conf    #再次更改端口
ansible-playbook --tags changetask   07 -nginx .yml   #重新启动执行playbook效果

4 综合实践[T]

暂定 未完待续。。。176

5. 变量进阶

ansible all -a "hostname" -o    #查看主机名
ansible all -m hostname -a "name=xxx"   #修改主机名
需求 想让三台主机的主机名不一样 用ansible如何来实现 例如
1
0.0.0.12   aaa
10.0.0.15   bbb
10.0.0.18   ccc

变量的多种设定方法

ansible 中有很多方式来设定变量,优先级从上到下依次增强。常见的方法有以下几种:    
1 目标主机默认的属性    
2 主机清单中定义的特有属性            /etc/ansible/hosts
3 playbook 通过 vars 定义的特有属性   例如:主机清单里面 vars的 值名:值变量
专用的 YAML 定义的特有属性文件  例:vars.yml  里面文件: qian:A hou:B  
命令行定义的特定属性      例:ansible/ansible-playbook -e qian=xxx 01-v.yml
定制主机名
ansible 10.0.0.12 -m hostname -a "name=ansible.example.com"

涉及4个属性:ansible_domain ansible_fqdn ansible_hostname ansible_nodename
定制 playbook.yml   文件名为01-v.yml
- hosts: allremote_user: roottasks:- name: create filefile:name: /var/log/var-{{ ansible_fqdn }}.logstate: touchowner: daemon
ansible-playbook 01-v.yml   #执行
ansible all -m shell -a "ls /var/log/var-* " -o          效果如下
结果显示:可以根据主机属性的方式获取独有的信息

1. 主机列表变量

/ etc / ansible / hosts 文件中定义主机变量主要有两种样式:公共变量普通变量
普通变量比公共变量的优先级高
普通变量  例如:
10.0.0.12  nginx_port = 83
实践:  文件名02-v.yml
- hosts: webremote_user: roottasks:- name: set hostnamehostname:name: ansible-{{ name }}.example.com

主机清单下改成这个

ansible web -m shell -a "hostname" -o    得到下面的结果
公共() 变量  例如:
[web_group : vars]
hostname = www
实践:  文件名03-v.yml
主机清单下改成这个
编写⼀个设定主机名的任务 03-v.yml
- hosts: webremote_user: roottasks:- name: set hostnamehostname: name={{ qian }}-{{ name }}{{ hou }}
nsible web -m shell -a "hostname" -o    得到下面的结果

2. 命令行

ansible命令
ansible 目标主机 - e 变量名 = 变量值 - m 模块 - a " 可执行命令 "
ansible 目标主机 - e ' 变量名 = 变量值 变量名 = 变量值 ' - m 模块 - a " 可执行命令 "
注意:可以直接设定多个环境变量名,彼此之间使用空格隔开,外侧使用单引号扩住即可。
ansible-playbook命令
ansible-playbook - e 变量名 = 变量值 playbook.yaml
ansible 命令设定变量
设定所有主机的 ip 地址
ansible web -e hou='.ansible.org' -m hostname -a "name={{ qian }}-{{ name }}{{ hou }}"  
ansible web -m shell -a "hostname" -o   效果如下

3. playbook实践

执行playbook 的时候,设定 qian 的值为bushiba
ansible-playbook - e qian=bushiba 02-v.yml
ansible web -m shell -a "hostname" -o   #效果如下

4. playbook变量基础

vars 格式
- hosts : web
 remote_user : root
 vars :    
- 变量名 : 变量值       
.. .
playbook 中专门设置变量的属性叫 vars
vars 中的变量是以列表的形式展示的
每一个变量都是以 " 变量名 : 变量值 " 的格式来展示的。
vars应用    文件名04-v.yml    
- hosts: webremote_user: rootvars:- head: ni- hostid: hao- tail: .shuai.comtasks:- name: set hostnamehostname:name: "{{ qian }}-{{ name }}{{ hou }}"

出来的结果不是想要的结果 疑?    待解决 
ansible-playbook 04-v.yml    执行
  
ansible web -m shell -a "hostname" -o   #查看结果

-e 设定的环境变量优先级高
ansible-playbook - e qian =nene   04 - v.yml
文件变量实践
playbook.yaml ⽬录下创建专⽤变量⽂件
vim vars.yaml
qian :  A
hou : .B
定制plybook文件 文件名06-v.yml
- hosts: webremote_user: rootvars_files:- vars.yamlvars:- head: www- tail: .ansible.toptasks:- name: set hostnamehostname: name={{ qian }}-{{ name }}{{ hou }}
ansible web -a "hostname" -o   查看效果 


6. 模板

Jinja2 是一种现代的、设计友好的 Python 模板语言,而 Ansible 作为自动化运维工具,大量使用 Jinja2 来处理配置文件、动态生成内容和实现复杂的逻辑控制。
Ansible 中, Jinja2 模板主要用于
使用 template 模块生成动态配置文件
playbook 中使用 {{ }} 语法进行变量插值
when 条件语句中使用 Jinja2 表达式
在循环 (with_items, with_dict ) 中处理复杂数据结构
清理之前的环境
ansible web - m service - a "name=nginx state=stopped"
ansible web - m yum  - a "name=nginx,nginx-common state=absent"
ansible web - m file - a "path=/data/webserver state=absent"
ansible web - m user - a "name=nginx-test state=absent"
案例实践
1. 准备基准配置⽂件
mkdir / data / ansible / playbook / templates / templates - p
cd / data / ansible / playbook / templates
2.定制主机清单
10.0.0.12  nginx_port = 81
10.0.0.15  nginx_port = 82
10.0.0.18  nginx_port = 83
3.改造基准配置文件     
vim templates/nginx-define.conf.j2
server {listen {{ nginx_port }};root /data/webserver/html;location / {}
}

4.改造playbook.yaml

vim /data/ansible/playbook/templates/01-template.yml
- hosts: webremote_user: roottasks:- name: install packageyum:name: nginxstate: present- name: create web rootfile:name: /data/webserver/htmlstate: directory- name: touch web indexshell: echo '<h1>welcome to ansible</h1>' > /data/webserver/html/index.html- name: delete default nginx conffile:name: /etc/nginx/sites-enabled/defaultstate: absent- name: copy configtemplate:src: ./templates/nginx-define.conf.j2dest: /etc/nginx/conf.d/nginx-define.confnotify:- restart nginx- name: start serviceservice:name: nginxstate: startedenabled: yeshandlers:- name: restart nginxservice:name: nginxstate: restarted
注:上面的文件只是将 copy 模块更改为了 template 模块
src 如果采用相对路径的话,其 根路径就是 playbook.yaml 所在目录

实践后期出现这个报错,但是01-template.yml 格式是正确的  原因是nginx有残留

做法:在每台主机上都yum autoremove 一下 清理掉nginx残存的东西

得到下面的结果

清理环境
ansible web - m service - a "name=nginx state=stopped"
ansible web - m yum  - a "name=nginx,nginx-common state=absent"
ansible web - m file - a "path=/data/webserver state=absent"

1.条件管理

在ansible动态生成配置文件的场景中,when语句可以对变量facts的值进行条件判断,从而实现不同的效果。
- hosts: webremote_user: roottasks:- name: install packageapt: name=nginx state=presentwhen: ansible_os_family == "RedHat"
位置: when 语句是针对条件判断是否执行动作的,所以他是 task 下面的一条配置项    
格式: when : 条件对象 判断操作符 判断值    
内容: when 语句中的条件对象可以是变量、 Facts 、命令结果等    
判断: when 语句中的条件判断操作符可以是以下几种类型:    
算术运算 + , - , , / , // , % , *    
比较操作 == , != , > , >= , < , <=    
逻辑运算 and, or, not, ( 表达式组 )
代码示例
# 满足多个条件
tasks :
- name : "shut down CentOS 6 systems"
   command : / sbin / shutdown - t now
   when :     
- ansible_facts[ 'distribution' ] == "CentOS"
- ansible_facts[ 'distribution_major_version' ] == "6"
# 判断某个变量是否存在信息 is defined
- name : Configure database connection
 template :
   src : db_config.j2
   dest : / etc / db.conf
 when : db_password is defined
案例实践 [ M ]   文件名02-when.yml
- hosts: webremote_user: roottasks:- name: ps_checkshell: ps -ef | grep nginx | grep -v grep | wc -lregister: nginx_numchanged_when: falseignore_errors: true- name: print debug messagedebug:msg: "System {{ inventory_hostname }} has nginx service."when: nginx_num.stdout != "0"- name: install packageyum:name: nginxstate: presentwhen: nginx_num.stdout == "0"- name: create web rootfile:name: /data/webserver/htmlstate: directory- name: touch web indexshell: echo '<h1>welcome to ansible</h1>' > /data/webserver/html/index.html- name: delete default nginx conffile:name: /etc/nginx/sites-enabled/defaultstate: absent- name: copy configtemplate:src: ./templates/nginx-define.conf.j2dest: /etc/nginx/conf.d/nginx-define.confnotify:- restart nginx- name: start serviceservice:name: nginxstate: startedenabled: yeshandlers:- name: restart nginxservice:name: nginxstate: restarted
ansible-playbook 02-when.yml - l 10.0.0.12
ansible-playbook 02-when.yml  - l 10.0.0.15
ansible web -m shell -a "netstat -tnulp | grep nginx"   测试结果如下
清楚环境
ansible web - m service - a "name=nginx state=stopped"
ansible web - m yum  - a "name=nginx,nginx-common state=absent"
ansible web - m file - a "path=/data/webserver state=absent"
ansible web - m user - a "name=nginx-test state=absent"

2.迭代管理  

- hosts: webremote_user: roottasks:- name: add usergroupgroup:name: webgroupstate: present- name: add several usersuser:name: "{{ item }}"state: presentgroups: webgroupwith_items:- testuser1- testuser2
即:在所有主机上都重复创建两个用户
ansible web -m shell -a "getent passwd | grep testu"
ansible web -m shell -a "getent group | grep testu"
所有主机上的用户都是两个,而且都加入到了 wheel 组。
清空环境
ansible web - m user - a "name=testuser1,testuser2,webgroup state=absent"
ansible web - m group - a "name=testuser1,testuser2,webgroup state=absent"
扩展 特定主机 安装软件实践
- hosts: webremote_user: roottasks:- name: install packageyum:name: "{{ item }}"state: presentwith_items:- 'nginx'- 'redis'- 'mariadb-server'
如果安装不成功的话,原因之一就是:远程主机上有对应的软件,需要把远程主机的软件移除即可
ansible web - m yum  - a "name=nginx,redis,mariadb-server state=absent"
3.多值迭代需求[M]
- hosts: webremote_user: roottasks:- name: add some groupuser:name: "{{ item }}"state: presentwith_items:- group1- group2- group3- name: add some usersuser:name: "{{ item.name }}"group: "{{ item.group }}"state: presentwith_items:- { name: 'user1', group: 'group1' }- { name: 'user2', group: 'group2' }- { name: 'user3', group: 'group3' }
ansible 10.0.0.15 -m shell -a "id user1"
清空环境
for i in user{ 1..3 } group { 1..3 } ; do ansible web - m user - a "name= $i state=absent" ; done

3.流程语法解析

{{  }} 用于表达式,比如变量、表达式等
{ %   % } 用于控制语句,比如 if for 等语句结构
{ # #} 用于注释,当模板文件被渲染后,该部分内容不会被显示

http://www.hkcw.cn/article/pnHCuCIyYp.shtml

相关文章

基于cornerstone3D的dicom影像浏览器 第二十七章 设置vr相机,复位视图

文章目录 前言一、VR视图设置相机位置1. 相机位置参数2. 修改mprvr.js3. 调用流程1) 修改Toolbar3D.vue2) 修改View3d.vue3) 修改DisplayerArea3D.vue 二、所有视图复位1.复位流程说明2. 调用流程1) Toolbar3D中添加"复位"按钮&#xff0c;发送reset事件2) View3d.vu…

以色列防长:哈马斯要么接受美方提案 要么面临毁灭

当地时间5月30日,以色列国防部长卡茨通过其个人社交媒体账号发表声明称,在以军强大的军事压力之下,巴勒斯坦伊斯兰抵抗运动(哈马斯)将被迫接受选择:接受美方提出加沙停火提案,或者被以色列消灭。△以色列国防部长卡茨(资料图)卡茨在声明中表示,当前以军正全力在加沙地…

古巴外交部召见美国临时代办 抗议其无礼行为

△古巴哈瓦那(资料图)当时间5月30日,古巴外交部召见了美国驻古巴临时代办迈克哈默(Mike Hammer)并表示,迈克哈默自2024年11月抵达古巴以来,对古巴表现出的不友好行为,既不符合他外交官的身份,也表现了对古巴人民的不尊重。古巴外交部美国双边事务总司主任加西亚向迈克…

Java处理动态的属性:字段不固定、需要动态扩展的 JSON 数据结构

引言 应用场景: 签名测试接口、表单配置项、参数列表、插件信息等。技术实现:JSONObject 接收、使用json格式的字符串,或者@JsonAnySetter/@JsonAnyGetter注解方法来处理动态的属性。I JSONObject 接收和返回 例子:表单配置 接口对应的表单配置信息 JSONObject 接收和返回…

leetcode1201. 丑数 III -medium

1 题目&#xff1a;1201. 丑数 III. 官方标定难度&#xff1a;中 丑数是可以被 a 或 b 或 c 整除的 正整数 。 给你四个整数&#xff1a;n 、a 、b 、c &#xff0c;请你设计一个算法来找出第 n 个丑数。 示例 1&#xff1a; 输入&#xff1a;n 3, a 2, b 3, c 5 输出…

【Oracle】DML语言

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. DML概述1.1 什么是DML&#xff1f;1.2 DML的核心功能 2. INSERT语句详解2.1 基础插入操作2.2 子查询插入2.3 多表插入2.4 批量插入优化 3. UPDATE语句详解3.1 基础更新操作3.2 关联更新3.3 批量更新优化 4. …

安装启动Mosquitto以及问题error: cjson/cJSON.h: No such file or directory解决

安装Mosquitto 在官方下载地址&#xff1a;https://mosquitto.org/files/source/ 选择版本下载 安装环境是linux centos7&#xff0c;上传 mosquitto-2.0.18.tar.gz 文件到 /mqtt 文件夹下 tar -xvf mosquitto-2.0.18.tar.gz #解压 cd mosquitto-2.0.18/ #切换到解压目录下…

附件上传唯一性校验

1. Overridepublic String uploadFile(MultipartFile file, String id, String funNo, String ctType) {//TODO 附件重复判断// 计算文件哈希值// 将MultipartFile转换为临时File对象String fileHash "";try {File tempFile convertMultipartFileToFile(file);// …

正点原子AU15开发板!板载40G QSFP、PCIe3.0x8和FMC LPC等接口,性能强悍!

正点原子AU15开发板&#xff01;板载40G QSFP、PCIe3.0x8和FMC LPC等接口&#xff0c;性能强悍&#xff01; 正点原子AU15开发板搭载Xilinx Artix UltraScale 系列FPGA&#xff0c;核心板主控芯片的型号是XCAU15P-FFVB676-2I。开发板由核心板&#xff0b;底板组成&#xff0c;外…

Attention-> flashAttention材料参考

1、 一文看懂 Attention&#xff08;本质原理3大优点5大类型&#xff09;_attention结构-CSDN博客2​​​​​​​2https://blog.csdn.net/haima1998/article/details/107845549 2、 一文看懂 NLP 里的模型框架 Encoder-Decoder 和 Seq2Seq (easyai.tech) 3、 详解深度学习…

MySQL高可用集群

https://dev.mysql.com/doc/mysql-shell/8.4/en/mysql-innodb-cluster.html 1 什么是MySQL高可用集群 MySQL高可用集群&#xff1a;MySQL InnoDB ClusterInnoDB Cluster是MySQL官方实现高可用读写分离的架构方案&#xff0c;包含以下组件 MySQL Group Replication&#xff1a;简…

山洪灾害声光电监测预警解决方案

一、方案背景 我国是一个多山的国家&#xff0c;山丘区面积约占国土面积的三分之二。每年汛期&#xff0c;受暴雨等因素影响&#xff0c;极易引发山洪和泥石流。山洪、泥石流地质灾害具有突发性、流速快、流量大、物质容量大和破坏力强等特点&#xff0c;一旦发生&#xff0c;将…

2025年最新工程项目管理系统应该具备哪些模块?

随着数字化转型浪潮席卷工程行业&#xff0c;工程项目管理系统的作用愈发凸显。2025年&#xff0c;工程项目管理系统的核心目标不仅是提升项目效率&#xff0c;更在于通过智能化、集成化技术实现全生命周期的精细化管理。基于行业趋势和企业实际需求&#xff0c;结合金众诚工程…

unity入门:同一文本不同颜色显示

unity入门&#xff1a;同一文本不同颜色显示 同一文本不同颜色显示#RRGGBBAA&#xff08;带透明度&#xff09;用法 同一文本不同颜色显示 在Unity中&#xff0c;如果想让文本中的某一部分显示不同的颜色&#xff0c;可以使用富文本(Rich Text)标记&#xff0c;在字符串中插入…

128、STM32H723ZGT6实现串口IAP

Bootloader程序通过串口接收*.bin文件数据&#xff0c;写入到内部flash区域&#xff0c;然后跳转APP应用程序 flash读写数据参考我的博客&#xff1a;127、stm32h743XI内部flash 注意&#xff1a;H723系列flash必须32字节写入&#xff0c;并且擦除时别重启|断电&#xff0c;不然…

【Netty系列】Reactor 模式 2

目录 流程图说明 关键流程 以下是 Reactor 模式流程图&#xff0c;结合 Netty 的主从多线程模型&#xff0c;帮助你直观理解事件驱动和线程分工&#xff1a; 流程图说明 Clients&#xff08;客户端&#xff09; 多个客户端&#xff08;Client 1~N&#xff09;向服务端发起连…

接口自动化测试用例的编写方法

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 phpunit 接口自动化测试系列 Post接口自动化测试用例 Post方式的接口是上传接口&#xff0c;需要对接口头部进行封装&#xff0c;所以没有办法在浏览器下直接调…

2025030给荣品PRO-RK3566开发板单独升级Android13的boot.img

./build.sh init ./build.sh -K ./build.sh kernel 【导入配置文件】 Z:\Android13.0\rockdev\Image-rk3566_t\config.cfg 【更新的内核】 Z:\Android13.0\rockdev\Image-rk3566_t\boot.img 【导入分区表&#xff0c;使用原始的config.cfg会出错的^_】 Z:\Android13.0\rockdev\…

伊拉克军方打死6名“伊斯兰国”武装分子

△伊拉克联合行动指挥部发布视频截图当地时间5月30日,伊拉克联合行动指挥部下属安全媒体中心发表声明称,29日晚至30日早间,伊军方出动战机对位于该国北部萨拉赫丁省沙伊谷地的极端组织“伊斯兰国”武装分子藏匿点发动空袭,打死了6名武装分子,并摧毁其藏匿点。(总台记者 米…

Python打卡训练营Day40

DAY 40 训练和测试的规范写法 知识点回顾&#xff1a; 彩色和灰度图片测试和训练的规范写法&#xff1a;封装在函数中展平操作&#xff1a;除第一个维度batchsize外全部展平dropout操作&#xff1a;训练阶段随机丢弃神经元&#xff0c;测试阶段eval模式关闭dropout 作业&#x…