【Docker】Docker学习03 | Docker的volume

news2024/9/23 17:24:04

本文首发于 ❄️慕雪的寒舍

1. 引入

在docker的基本知识讲解中,提到了docker镜像是由一层一层文件系统构成的。这一系列文件系统是一系列的只读层。当我们创建一个容器的时候,Docker会读取镜像(只读),并在镜像的顶部再添加一层读写层

这种读写层和只读层的组合被称为联合文件系统(Union File System / Unoin FS),结构抽象如下表所示,以防图片加载不出来。

层级说明
Running Container正在运行的容器
Storage Driver存储驱动层
write layer读写层
image layer镜像只读层
HOST宿主机

image.png

如果正在运行的容器修改了现有的文件,这些文件会被拷贝出底层的只读层,放到最顶部的容器读写层中,读写层中文件的未修改版本仍然存放在镜像的只读层中。

文件说明
读写层app.ini当出现写操作的时候,从只读层中拷贝到读写层
只读层app.ini

当基于相同的镜像创建第二个容器时,还是会创建一个没有任何数据修改的全新容器。在之前的容器中的任何修改只会保留在原有容器中,实现了容器和镜像的隔离。

这种读写层的操作带来了以下的问题:

  1. 当容器不再存在的时候,数据不持久化;
  2. 如果另外一个进程需要使用容器内的数据,难以将其从容器内取出;
  3. 容器的可写层与容器当前运行的宿主机紧密相连,难以将其移动到另外一台主机上;
  4. 写入容器的可写层需要存储驱动Storage Dirver来管理这个文件系统,存储驱动提供了一个使用Linux内核的联合文件系统;与直接将数据写入宿主机的文件系统的方式,这种额外的抽象层降低了性能。

为了能持久化这些修改过的数据,并且能够很容易实现容器间进行数据的共享,docker提出了volume的概念,同时也提供了多种数据持久化的方式。

2. docker提供的持久化策略

docker提供两种文件持久化的策略,分别是volume和mount,其中mount还分为bind mount(将容器内路径和宿主机的文件路径绑定)和tmpfs mount(数据只存在于宿主机的内存中)。

通过volume和bind mount持久化的文件都可以称之为docker的数据卷。数据卷是在容器默认的联合文件系统之外的文件或目录,它可以在宿主机上直接被访问。即便容器删除,数据卷中的内容也不会丢失。

image.png

tips:

  • Volumes are stored in a part of the host filesystem which is managed by Docker (/var/lib/docker/volumes/ on Linux). Non-Docker processes should not modify this part of the filesystem. Volumes are the best way to persist data in Docker.
  • Bind mounts may be stored anywhere on the host system. They may even be important system files or directories. Non-Docker processes on the Docker host or a Docker container can modify them at any time.
  • tmpfs mounts are stored in the host system’s memory only, and are never written to the host system’s filesystem.

下文将对这三种不同的文件持久化方式进行测试

3. volumes

3.1. 测试:自动创建的volume

mysql:5.7镜像为例,下面是一个创建容器的命令

docker run -d \
	--name="testMysql" \
	-e MYSQL_ROOT_PASSWORD="123456" \
	mysql:5.7

创建容器之前,先看看当前系统上的docker volume有哪些

$ docker volume ls
DRIVER    VOLUME NAME
local     53b8da5cc9f94a856e263d36ae69aea754be90a5a8b5b4848850af6e35503770
local     act-toolcache

执行了这个命令后,mysql容器被创建且正常运行,再次查看当前系统上的docker volume,可以发现多了一个新的volume。

DRIVER    VOLUME NAME
local     0cd65f1432c653ec08d7d8c3c50f645b97e0f26d139f1debb0c7fead3dafdfa4
local     53b8da5cc9f94a856e263d36ae69aea754be90a5a8b5b4848850af6e35503770
local     act-toolcache

进入新创建的这个docker volume在宿主机上的路径,看看这里面有什么东西

❯ sudo ls -al /var/lib/docker/volumes/0cd65f1432c653ec08d7d8c3c50f645b97e0f26d139f1debb0c7fead3dafdfa4/_data
total 188484
drwxrwxrwt 5  999 docker     4096 May  6 16:56 .
drwx-----x 3 root root       4096 May  6 16:56 ..
-rw-r----- 1  999 docker       56 May  6 16:56 auto.cnf
-rw------- 1  999 docker     1676 May  6 16:56 ca-key.pem
-rw-r--r-- 1  999 docker     1112 May  6 16:56 ca.pem
-rw-r--r-- 1  999 docker     1112 May  6 16:56 client-cert.pem
-rw------- 1  999 docker     1676 May  6 16:56 client-key.pem
-rw-r----- 1  999 docker     1318 May  6 16:56 ib_buffer_pool
-rw-r----- 1  999 docker 79691776 May  6 16:56 ibdata1
-rw-r----- 1  999 docker 50331648 May  6 16:56 ib_logfile0
-rw-r----- 1  999 docker 50331648 May  6 16:56 ib_logfile1
-rw-r----- 1  999 docker 12582912 May  6 16:56 ibtmp1
drwxr-x--- 2  999 docker     4096 May  6 16:56 mysql
lrwxrwxrwx 1  999 docker       27 May  6 16:56 mysql.sock -> /var/run/mysqld/mysqld.sock
drwxr-x--- 2  999 docker     4096 May  6 16:56 performance_schema
-rw------- 1  999 docker     1680 May  6 16:56 private_key.pem
-rw-r--r-- 1  999 docker      452 May  6 16:56 public_key.pem
-rw-r--r-- 1  999 docker     1112 May  6 16:56 server-cert.pem
-rw------- 1  999 docker     1676 May  6 16:56 server-key.pem
drwxr-x--- 2  999 docker    12288 May  6 16:56 sys

如果你对MySQL比较熟悉,应该就能认出来,这就是MySQL在/var/lib/mysql中存放的数据,我们可以做个简单的验证,使用如下命令,直接链接到这个新创建的容器的MySQL命令行中。

docker exec -it testMysql mysql -uroot -p123456

我们在MySQL里面创建一个testdb数据库和一个stu表

-- 创建数据库
create database testdb;
-- 进入testdb数据库
use testdb;
-- 创建stu表
create table stu(
	id int primary key,
	name varchar(30) NOT NULL
);

操作完成后,exit退出容器,再次查看刚刚的volume目录。可以看到多了一个名为testdb的文件夹。

❯ sudo ls -al /var/lib/docker/volumes/0cd65f1432c653ec08d7d8c3c50f645b97e0f26d139f1debb0c7fead3dafdfa4/_data
total 188488
drwxrwxrwt 6  999 docker     4096 May  6 17:15 .
drwx-----x 3 root root       4096 May  6 16:56 ..
-rw-r----- 1  999 docker       56 May  6 16:56 auto.cnf
-rw------- 1  999 docker     1676 May  6 16:56 ca-key.pem
-rw-r--r-- 1  999 docker     1112 May  6 16:56 ca.pem
-rw-r--r-- 1  999 docker     1112 May  6 16:56 client-cert.pem
-rw------- 1  999 docker     1676 May  6 16:56 client-key.pem
-rw-r----- 1  999 docker     1318 May  6 16:56 ib_buffer_pool
-rw-r----- 1  999 docker 79691776 May  6 17:15 ibdata1
-rw-r----- 1  999 docker 50331648 May  6 17:15 ib_logfile0
-rw-r----- 1  999 docker 50331648 May  6 16:56 ib_logfile1
-rw-r----- 1  999 docker 12582912 May  6 16:56 ibtmp1
drwxr-x--- 2  999 docker     4096 May  6 16:56 mysql
lrwxrwxrwx 1  999 docker       27 May  6 16:56 mysql.sock -> /var/run/mysqld/mysqld.sock
drwxr-x--- 2  999 docker     4096 May  6 16:56 performance_schema
-rw------- 1  999 docker     1680 May  6 16:56 private_key.pem
-rw-r--r-- 1  999 docker      452 May  6 16:56 public_key.pem
-rw-r--r-- 1  999 docker     1112 May  6 16:56 server-cert.pem
-rw------- 1  999 docker     1676 May  6 16:56 server-key.pem
drwxr-x--- 2  999 docker    12288 May  6 16:56 sys
drwxr-x--- 2  999 docker     4096 May  6 17:15 testdb

查看该文件夹,能看到刚刚我们创建的stu表的本地文件。可见这就是MySQL的本地路径。如果你在宿主机上直接使用apt安装一个MySQL/MariaDB,也可以在宿主机的/var/lib/mysql中看到类似的文件。

❯ sudo ls -al /var/lib/docker/volumes/0cd65f1432c653ec08d7d8c3c50f645b97e0f26d139f1debb0c7fead3dafdfa4/_data/testdb
total 120
drwxr-x--- 2 999 docker  4096 May  6 17:15 .
drwxrwxrwt 6 999 docker  4096 May  6 17:15 ..
-rw-r----- 1 999 docker    65 May  6 17:15 db.opt
-rw-r----- 1 999 docker  8586 May  6 17:15 stu.frm
-rw-r----- 1 999 docker 98304 May  6 17:15 stu.ibd

通过docker inspect testMysql命令,可以查询到这个容器的配置详情,其中的Mount部分就有刚刚看到的volume,其中Source字段就是这个volume在宿主机上的路径,Destination字段是volume对应的容器内路径。

{
        "Mounts": [
            {
                "Type": "volume",
                "Name": "0cd65f1432c653ec08d7d8c3c50f645b97e0f26d139f1debb0c7fead3dafdfa4",
                "Source": "/var/lib/docker/volumes/0cd65f1432c653ec08d7d8c3c50f645b97e0f26d139f1debb0c7fead3dafdfa4/_data",
                "Destination": "/var/lib/mysql",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ]
}

再去找找MySQL容器的dockerfile,也可以在里面看到一行关于volume的配置

VOLUME /var/lib/mysql

由此可见,对于创建容器,如果没有在run命令中主动mount某个volume或路径时,docker会自动创建一个随机命名的volume(保持唯一性),并将容器内的路径和这个volume绑定。

image.png

另外,一个volume的只能对应容器内的一个路径。如果容器在dockerfile中指定了多个不同路径的volume,则Docker也会创建多个volume与之对应。

3.2. 测试:主动指定volume

我们可以在run命令中指定容器路径和某个volume进行绑定,也可以写入一个volume的名字,在创建容器的同时创建这个volume。

下面这两种创建方式,都会在/var/lib/docker/volumes中创建一个名为test_mysql_2的volume。

# 创建volume
docker volume create test_mysql_2
# 绑定
docker run -d \
	--name="testMysql2" \
	-v test_mysql_2:/var/lib/mysql \
	-e MYSQL_ROOT_PASSWORD="123456" \
	mysql:5.7
# 创建容器的时候直接创建volume
docker run -d \
	--name="testMysql2" \
	-v test_mysql_2:/var/lib/mysql \
	-e MYSQL_ROOT_PASSWORD="123456" \
	mysql:5.7

执行命令后,可以看到新创建出来的volume

❯ docker volume ls
DRIVER    VOLUME NAME
local     0cd65f1432c653ec08d7d8c3c50f645b97e0f26d139f1debb0c7fead3dafdfa4
local     53b8da5cc9f94a856e263d36ae69aea754be90a5a8b5b4848850af6e35503770
local     act-toolcache
local     test_mysql_2

通过docker inspect testMysql2命令,可以看到Mount中的信息

{
        "Mounts": [
            {
                "Type": "volume",
                "Name": "test_mysql_2",
                "Source": "/var/lib/docker/volumes/test_mysql_2/_data",
                "Destination": "/var/lib/mysql",
                "Driver": "local",
                "Mode": "z",
                "RW": true,
                "Propagation": ""
            }
        ]
}

3.3. 绑定volume的权限选项

这里能发现字段Mode有变化,由空串变成了小写的z。这个是什么意思呢?

  • z(小写):代表绑定的目录由多个容器共享,其他容器也可以挂载这个volume;
  • Z(大写):代表绑定的目录由单个容器私有,其他容器无法挂载;

在使用-v绑定某个路径的时候,可以在路径后面再添加一个选项,来指定权限和绑定模式。方式如下,在容器内路径后再追加一个冒号

	-v volume名字或宿主机路径:容器内路径:[权限选项]

权限的可选项有四种,默认情况下,给定的是rw读写权限。

  • 大写Z
  • 小写z
  • ro(只读)
  • rw(读写)

其中:z:Z选项是和SELinux有关的,具体可以参考官方文档和Linux中国的文章。

在Ubuntu上,SELinux工具集默认应该是没有启用的。

注意,如果你使用:Z(大写)选项绑定了宿主机中诸如//usr/home的目录,你可能会因为权限问题,直接无法使用宿主机!使用该选项的时候需要慎重!

4. mount

4.1. bind mount

4.1.1. 说明

bind mount是docker早期就已经存在的数据持久化方式,其支持将容器的内的路径映射到某个宿主机上的路径,实现容器和宿主机文件的同步。绑定挂载直接使用了宿主机的文件系统,性能更佳。

绑定路径在docker run命令中和volume类似,都可以使用-v选项来实现

	-v 宿主机路径:容器内路径

下面是一个示例

# 使用root用户,在宿主机上创建路径
mkdir /data/mysql
# docker容器绑定这个路径
docker run -d \
	--name="testMysql3" \
	-v /data/mysql:/var/lib/mysql \
	-e MYSQL_ROOT_PASSWORD="123456" \
	mysql:5.7

这样这个docker安装的MySQL容器内的所有数据都会被写入宿主机的/data/mysql路径中,我们可以直接备份这个路径实现对MySQL数据的保留。

image.png

4.1.2. 源路径的说明

注意绑定挂载时-v选项中的路径volume的区别。我们知道,在Linux命令行中,直接输入一个目录/文件的名称,会默认是当前路径下的内容

cd  folder   等价于 cd ./folder
vim test.txt 等价于 vim ./test.txt

而在docker run命令的-v选项中,源路径source输入直接为某个目录名的时候,会认为是volume的名称!而不是当前路径下的文件!

假设我们当前运行docker run的终端路径中有一个folder文件夹,我们想将这个文件夹映射到docker容器内的/data路径,推荐的写法如下(推荐使用绝对路径来设置源主机上的路径)。

	-v ${PWD}/folder:/data

错误的写法如下,直接写一个folder会以之为名创建一个新的volume,不符合我们的需要!

	-v folder:/data

这一点在新建容器的时候一定要注意!个人推荐维持一个原则,即使用bind mount的时候一定要用绝对路径来设置宿主机上的文件路径。

4.1.3. bind mount的弊端

绑定挂载也有弊端

  • Bind mounts allow access to sensitive files One side effect of using bind mounts, for better or for worse, is that you can change the host filesystem via processes running in a container, including creating, modifying, or deleting important system files or directories. This is a powerful ability which can have security implications, including impacting non-Docker processes on the host system.

翻译过来就是,绑定挂载(特别是以读写方式挂载)会让docker容器有权限修改宿主机的任何文件,甚至包括宿主机的系统文件。存在安全性问题。

这一点在Linux中国关于SELinux的文章中就有介绍,比如我们将宿主机的/路径直接绑定到容器的/test路径中时,使用docker exec进入这个容器的终端,我们会拥有容器内的root权限(即可以对当前登录的这个容器内的文件做任意修改),此时就直接可以通过编辑容器内的/test路径,来删除/修改宿主机上的重要文件。

4.1.4. docker run 的 --mount 选项

除了-v选项,还可以用--mount选项来挂载数据卷,效果一致。

docker run -d \
	--name="testMysql4" \
	--mount type=bind,source=/data/mysql,target=/var/lib/mysql \
	-e MYSQL_ROOT_PASSWORD="123456" \
	mysql:5.7

mount选项中,绑定的选项都用参数名写出来了,相对来说会更好理解,但是命令也变得复杂了。

keyvalue
typebind/volume/tmpfs
source/srcdocker host上的一个目录或文件
destination/dst/target容器内的一个目录或文件
readonly挂载为只读
option额外选项

如果需要指定readonly,直接在target后面添加该选项即可。添加了只读选项后,容器内对于这个路径就只能读,不能写入了。

--mount type=bind,source=/data/mysql,target=/var/lib/mysql,readonly

当使用mount选项来绑定volume的时候,可以省略type,此时docker会自动以source写入的字符串作为volume的名字,创建一个新volume并与当前容器进行绑定。

docker run -d \
	--name="testMysql4" \
	--mount source=mysql_vol,target=/var/lib/mysql \
	-e MYSQL_ROOT_PASSWORD="123456" \
	mysql:5.7

4.2. tmpfs mount

当容器为了性能原因,需要高频读写某些缓存文件(比如jellyfin镜像就有一个cache目录的volume,内部是一些缓存文件),或者为了安全性考虑不打算将一些数据写入磁盘的时候,我们可以使用tmpfs mount,将指定的路径绑定到宿主机的内存上。

对于nginx容器而言,其默认会有一个nginx的欢迎页面,存放在/usr/share/nginx/html路径中,这个欢迎页面可能会被经常的读取,占用空间也不大,所以我们可以将其放入内存中。

可以使用mount选项来进行绑定

# 直接绑定
docker run -d -it \
  -p 80:80 \
  --name tmptest \
  --mount type=tmpfs,target=/usr/share/nginx/html \
  nginx:latest
# 绑定时添加权限选项,1770代表全局可写
docker run -d -it \
  -p 80:80 \
  --name tmptest \
  --mount type=tmpfs,target=/usr/share/nginx/html,tmpfs-mode=1770 \
  nginx:latest

也可以使用tmpfs选项来绑定

docker run -d -it \
  -p 80:80 \
  --name tmptest \
  --tmpfs /usr/share/nginx/html \
  nginx:latest

更多相关的参数,可以参考docker的官方文档storage/tmpfs。

4.3. bind mount和volume的区别

docker官方其实一直都推荐我们使用volume来实现数据持久化,而不是使用bind mount。来看看二者的区别吧。

区别bind mountvolume
source位置任意指定/var/lib/docker/volumes
source路径为空覆盖容器中的内容容器内数据复制到volume
权限控制读写/只读读写/只读
单个文件支持不支持,只能是目录
移植性弱,与hostpath绑定强,无需指定hostpath

5. 持久化和数据卷

数据卷的最大特点是它的生命周期独立于容器的生命周期,即便容器被删除,数据卷中的内容也不会被删除(tmpfs除外,它的内容本来就没有写入磁盘)。当使用docker rm删除某个容器的时候,docker并不会主动删除和容器关联的数据卷。

  • 数据卷可在容器之间共享或重用数据。
  • 数据卷的更改可以直接生效。
  • 数据卷的生命周期一直持续到没有容器使用它为止。
  • 对数据卷操作不会影响到镜像本身。
  • 数据卷可以完成容器到宿主机、宿主机到容器以及容器到容器之间的数据共享。

可见数据卷的好处还是多多的。所以,当你打算删除某个数据卷的时候,一定要确保这个数据卷里面的文件是完全无用了!

6. 参考文档

  • 理解并正确使用docker volume/bind mount
  • docker volume详解
  • Understanding Volumes in Docker

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

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

相关文章

SpringBoot集成google登陆快速入门Demo

1.为何要使用 Google 账号登录 借助“使用 Google 账号登录”功能,您可通过安全性备受信赖的 Google 账号,轻松快捷地在网上登录和注册网站与应用。该功能可消除您对密码的依赖,从而降低使用密码带来的困扰和安全风险。 2.环境准备 登录 G…

【IEEE出版】第八届电气、机械与计算机工程国际学术会议(ICEMCE 2024,10月25-27)

由西京学院主办,AEIC学术交流中心协办,中国科学技术大学、深圳大学、浙江工业大学等校联合支持的第八届电气、机械与计算机工程国际学术会议(ICEMCE 2024)将于2024年10月25日至27日在西安举办。 本次会议主要围绕“电气”、"…

【文档】软件项目售后服务标准文档参考(word原件)

软件售后服务方案的售后服务范围广泛,涵盖了多个方面,以确保客户在使用软件过程中得到全面、及时的支持。具体来说,这些服务范围通常包括以下几个核心内容: 技术支持服务维护与更新服务培训与教育服务定制化服务数据管理与服务客户…

[C语言]一、C语言基础(函数)

G:\Cpp\C语言精讲 6. 函数 6.1函数的基本使用 6.1.1 为什么需要函数 《街霸》游戏中,每次人物出拳、出脚或跳跃等动作都需要编写50-80行的代码,在每次出拳、出脚或跳跃的地方都需要重复地编写这50-80行代码,这样程序会变得很臃肿&#xff…

[学习笔记]深度学习详解-Datawhale学习组

第三章:深度学习基础 3.1 局部极小值与鞍点 3.1.1 临界点及其种类 优化神经网络时,使用梯度下降法,遇到梯度为0的点,训练就停了下来,损失也不再下降。 这个梯度为0的点,可以称为临界点。 临界点可以细分…

在挫折感中遇见更好的自己

你是如何克服编程学习中的挫折感的? 编程学习之路上,挫折感就像一道道难以逾越的高墙,让许多人望而却步。然而,真正的编程高手都曾在这条路上跌倒过、迷茫过,却最终找到了突破的方法。你是如何在Bug的迷宫中找到出口的…

ssrf+redisssrf+fastcgi

curl支持很多协议,有FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET, DICT, FILE以及LDA ssrfredis dict被禁用了用(?urlhttp://172.19.0.3端口)来探测一下端口吧 172.19.0.3主机只开放一个80端口 看看内网还有其他服务器没 这里可以看到内网还有…

Ai+若依(代码生成 -- 树表“有层级关系的”):【03篇】

代码生成 代码生成器,根据数据库表结构自动生成前后端CRUD代码提供三种生成模板:单表、树表、主子表(一对多)现在来说说树表,主子表 树表: 例如:公司==》部门==》员工 层级关系的这种 主子表: 例如: 数据之间存在一对多,比如菜品和口味表 一个菜品可以多个口味 自动化…

图形几何算法 -- 判断两条线段是否相交

线段相交检测是计算几何中的一个基本问题,广泛应用于计算机图形学、游戏开发、物理模拟等领域。我们可以通过以下步骤和理论来判断两条线段是否相交。 概念 在二维平面上,给定两条线段 A(P1, P2) 和 B(Q1, Q2),我们需要判断这两条线段是否相…

鸿蒙内核源码分析(双向链表) | 谁是内核最重要结构体?

答案一定是: LOS_DL_LIST(双向链表)&#xff0c;它长这样. typedef struct LOS_DL_LIST {//双向链表&#xff0c;内核最重要结构体struct LOS_DL_LIST *pstPrev; /**< Current nodes pointer to the previous node *///前驱节点(左手)struct LOS_DL_LIST *pstNext; /**<…

Linux-部署YUM仓库及NFS共享服务

系列文章目录 提示&#xff1a;仅用于个人学习&#xff0c;进行查漏补缺使用。 1.Linux-网络设置 2.Linux-DHCP服务、vsftp 3.Linux-DNS域名解析服务 4.Linux-远程访问及控制 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档…

【GIS系列】多源异构原始影像解析:策略模式与规则引擎的应用

作者&#xff1a;后端小肥肠 &#x1f347; 我写过的文章中的相关代码放到了gitee&#xff0c;地址&#xff1a;xfc-fdw-cloud: 公共解决方案 &#x1f34a; 有疑问可私信或评论区联系我。 &#x1f951; 创作不易未经允许严禁转载。 1. 前言 在遥感技术和地球观测领域&#…

机器学习周报(8.19-8.25

文章目录 摘要Abstract1.PyTorch环境的配置及安装使用PyCharm配置环境安装配置jupyter 2.两个Python常用函数3.DataSet4.TensorBoard的使用绘制一幅坐标图使用tendorboard对一幅图片进行操作 5.torchvison中的transforms总结 摘要 在之前学习了一些机器学习相关理论之后&#…

【限时免费发放】2000+热门Scratch作品源码

欢迎访问小虎鲸Scratch资源站&#xff01;在Scratch编程的学习过程中&#xff0c;优质的资源和灵感是至关重要的。因此&#xff0c;我们特别准备了这份【免费下载】的Scratch作品源码合集&#xff0c;包含超过2000个精选的Scratch项目源码&#xff0c;旨在为Scratch编程爱好者和…

Nginx+keepalived实现高可用

目录 一、准备工作 1、安装软件 二、配置master主服务器 1、修改nginx主配置文件 ​编辑 2、修改keepalived主配置文件 三、配置backup备服务器 四、配置节点服务器 1、配置第一个节点服务器 1.1、设置虚拟网卡 1.2、忽略ARP请求 1.3、安装并启动nginx软件 2、配置…

【STM32】SPI接口(非连续传输)

本篇博客重点在于标准库函数的理解与使用&#xff0c;搭建一个框架便于快速开发 目录 前言 SPI简介 IO口初始化 SPI配置 时钟使能 SPI初始化 SPI使能 数据接收与发送 硬件SPI代码 MySPI.h MySPI.c 前言 【通信协议】SPI总线-CSDN博客 本篇博客学习使用STM32的…

Expo 开发ReactNative 后切换 eas 账号

修改slug app.json中的sulg字段更新为新账号应用sulg 修改projectId app.json中的extra.eas.projectId字段更新为新账号应用projectId 退出账号&#xff1a; eas logout 重新登录&#xff1a; eas login

基于WEB的学生综合测评系统的设计与实现

第1章 绪 论 1.1 系统开发背景 随着计算机技术的不断发展,在现代化社会中,信息的处理越来越依赖计算机来完成。在没有测评系统之前&#xff0c;所有的信息记录都是由人工记录维护&#xff0c;不但不方便&#xff0c;还经常出错&#xff0c;有了测评系统就可以方便的对各种信息…

.net maui安卓开发中使用明文传输(一)

背景:最近在做一个pad上的项目,目的是执行每日点检功能(就是检查设备的各项保养指标);前期用HBuilder做了一个,但是现场的触摸屏选用的是TouchPie 安卓版本是6.0版本,上次开发的软件可以在安卓7.0上完美兼容,但由于触摸屏安卓版本太低不能兼容;询问厂商才知道这款触摸…

【Datawhale AI夏令营】从零上手CV竞赛Task1

【Datawhale AI夏令营】从零上手CV竞赛Task1 前言赛事官网学习任务TASK 1 前言 这个暑假我通过微信群关注到了【Datawhale AI夏令营】&#xff0c;并且记录我的代码学习以及调试的过程。 赛事官网 赛事官网&#xff1a;https://www.marsbigdata.com/competition/details?id…