当前位置: 首页 > news >正文

容器技术基础理论与常用命令:必知必会,效率翻倍!

如何利用容器技术提升你的工作效率?掌握基础理论和常用命令是必不可少的,本文将为你全面介绍容器技术,并教你必知必会的技能,让你工作、学习效率翻倍,对于网络安全工作者也是必不可少的技能!

0. 引言

学习容器技术对大家的日常工作和学习都有很多好处,主要如下:

  • 提高开发效率:使用容器技术可以快速搭建开发环境和部署环境,大大提高了开发效率。

  • 更好的可移植性:容器技术使得应用程序更易于在不同的操作系统和云平台之间移植,从而实现更好的可移植性。

  • 更好的资源利用率:容器可以在相同的硬件资源上运行更多的应用程序,从而更好地利用硬件资源。

  • 更好的安全性:容器技术通过隔离应用程序和操作系统,提供了更好的安全性,防止应用程序之间的相互干扰和攻击。

  • 更好的可扩展性:容器技术可以轻松地进行水平和垂直扩展,从而更好地应对高并发和大流量的需求。

另,学习容器技术对于网络安全领域的工作者更是有以下好处:

  • 更好地理解应用程序:容器技术可以帮助网络安全工作者更好地理解应用程序的运行机制,因为容器技术可以将应用程序及其依赖项打包成一个可移植的整体;

  • 更好地管理应用程序:容器技术可以提供更好的应用程序管理和部署机制,可以帮助网络安全工作者更好地控制应用程序的运行环境,减少潜在的安全漏洞;

    博主搭建的漏洞环境、漏洞靶场也几乎都是容器化部署的。

  • 更好地隔离应用程序:容器技术可以提供更好的应用程序隔离机制,可以将不同的应用程序隔离开来,从而减少由于应用程序之间相互干扰导致的安全问题;

  • 更好地应对攻击:容器技术可以提供更好的应对攻击的机制,例如通过容器镜像签名来确保容器镜像来源的可靠性,以及通过容器网络隔离来限制容器之间的通信等。

1. 基础理论

1.1. 什么是容器(Container)

容器是一种统一的软件交付的标准,所构建的软件包(容器镜像)可以跨平台(Linux或Windows)随处运行,可以对以下场景进行隔离:

  • 应用配置:如数据源配置,应用端口配置等;
  • 业务应用:如购物网站,SaaS服务等
  • 系统软件:如openssl、gcc、curl、python、jdk等;
  • 系统配置:如防火墙策略配置iptables;
  • 操作系统:RedHat、Ubuntu、CentOS等。

1.1.1. 容器与虚拟机的区别

容器技术起源于Linux,是一种内核虚拟化技术,提供轻量级的虚拟化,以便隔离进程和资源。尽管容器技术已经出现很久,却是随着Docker的出现而变得广为人知。Docker是第一个使容器能在不同机器之间移植的系统。 Docker 简化了打包应用的流程、打包应用的库和依赖,甚至整个操作系统的文件系统能被打包成一个简单的可移植的包,这个包可以被用来在任何其他运行Docker的机器上使用。

容器和虚拟机具有相似的资源隔离和分配方式,容器虚拟化了操作系统而不是硬件,更加便携和高效。

容器 vs 虚拟机

对比指标容器虚拟机备注
磁盘占用镜像层最小可至KB级别,虚拟机大小一般为GB级别
启动速度传统的虚拟机技术启动应用服务往往需要数分钟,而Docker容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间,大大节约了开发、测试、部署的时间。
并发宿主机可启动成百上千个容器,但虚拟机至多同时启动几十个
性能较高较差容器性能接近宿主机本地进程,虚拟机进程逊于宿主机本地进程
资源利用率由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,容器对系统资源的利用率更高。
维护扩展性Docker使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker团队同各个开源项目团队一起维护了大批高质量的官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。

1.2. 镜像(Image)是什么

将应用软件及所有相关的交付件统一打成一个包,这个包称为镜像,镜像可通过容器引擎快速运行。Docker Hub 中 95%+ 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。比如我们现在构建一个新的镜像,Dockerfile 如下:

FROM debian
RUN apt-get install emacs
RUN apt-get install apache2
CMD ["/bin/bash"]

注解:

  • Dockerfile是一个文本文档,其中包含用户可以在命令行上调用以组装镜像的所有命令。Docker可以通过读取Dockerfile中的指令自动构建镜像;
  • 如果多个镜像都从相同的base镜像构建而来,那么Docker主机上只需在磁盘上保存一份base镜像。同时内存中也只需加载一份base镜像(即镜像的每一层都可以被共享),就可以为所有容器服务了。

1.3. 什么是镜像仓库(Image Registry)

镜像仓库用于存放镜像,以及促进不同人和不同电脑之间共享这些镜像。当编译镜像时,要么可以在编译它的电脑上运行,要么可以先上传镜像到一个镜像仓库,然后下载到另外一台电脑上并运行它。Docker Hub便是一个用于存放Docker镜像的在线仓库,它可以存放私人和公开的镜像。

在这里插入图片描述

1.4. 什么是卷(Volume)

容器中的文件在磁盘上是临时存放的,当容器重建时,容器中的文件将会丢失,另外当在一个 Pod 中同时运行多个容器时,常常需要在这些容器之间共享文件,这也是容器不好解决的问题。K8s 抽象出了 Volume 来解决这两个问题,也就是存储卷,K8s的Volume是Pod的一部分,Volume不是单独的对象,不能独立创建,只能在Pod中定义。

Pod中的所有容器都可以访问Volume,但必须要挂载,且可以挂载到容器中任何目录。

注意:数据卷类似于Linux下对目录或文件进行mount,镜像中的被指定为挂载点的目录中的文件会复制到数据卷中(仅数据卷为空时会复制)。

1.5. 什么是K8S

Kubernetes是一个开源的容器编排部署管理平台,用于管理云平台中多个主机上的容器化应用。Kubernetes的目标是让部署容器化的应用简单并且高效,Kubernetes提供了应用部署、规划、更新、维护的一种机制。K8S架构图如下:

对应用开发者而言,可以把Kubernetes看成一个集群操作系统。Kubernetes提供服务发现、伸缩、负载均衡、自愈甚至选举等功能,让开发者从基础设施相关配置等解脱出来。

Kubernetes可以把大量的服务器看做一台巨大的服务器,在一台大服务器上面运行应用程序。无论Kubernetes的集群有多少台服务器,在Kubernetes上部署应用程序的方法永远一样。

1.5.1. Kubernetes中的基本对象

下图中介绍了Kubernetes中基本对象及它们之间的一些关系。

Kubernetes基本对象

  • 容器组(Pod):Pod是Kubernetes创建或部署的最小单位。一个Pod封装一个或多个容器(container)、存储资源(volume)、一个独立的网络IP以及管理控制容器运行方式的策略选项。

  • 无状态工作负载(Deployment):Deployment是对Pod的服务化封装。一个Deployment可以包含一个或多个Pod,每个Pod的角色相同,所以系统会自动为Deployment的多个Pod分发请求。

  • 有状态工作负载(StatefulSet):StatefulSet是用来管理有状态应用的对象。和Deployment相同的是,StatefulSet管理了基于相同容器定义的一组Pod。但和Deployment不同的是,StatefulSet为它们的每个Pod维护了一个固定的ID。这些Pod是基于相同的声明来创建的,但是不能相互替换,无论怎么调度,每个Pod都有一个永久不变的ID。

  • 任务(Job):Job是用来控制批处理型任务的对象。批处理业务与长期伺服业务(Deployment)的主要区别是批处理业务的运行有头有尾,而长期伺服业务在用户不停止的情况下永远运行。Job管理的Pod根据用户的设置把任务成功完成就自动退出(Pod自动删除)。

  • 定时任务(CronJob):CronJob是基于时间控制的Job,类似于Linux系统的crontab,在指定的时间周期运行指定的任务。

  • 守护进程集(DaemonSet):DaemonSet是这样一种对象(守护进程),它在集群的每个节点上运行一个Pod,且保证只有一个Pod,这非常适合一些系统层面的应用,例如日志收集、资源监控等,这类应用需要每个节点都运行,且不需要太多实例,一个比较好的例子就是Kubernetes的kube-proxy。

  • 服务(Service):Service是用来解决Pod访问问题的。Service有一个固定IP地址,Service将访问流量转发给Pod,而且Service可以给这些Pod做负载均衡。

    在这里插入图片描述

  • 路由(Ingress):Service是基于四层TCP和UDP协议转发的,Ingress可以基于七层的HTTP和HTTPS协议转发,可以通过域名和路径做到更细粒度的划分。

  • 配置项(ConfigMap):ConfigMap是一种用于存储应用所需配置信息的资源类型,用于保存配置数据的键值对,可在容器工作负载中作为文件或者环境变量使用。通过ConfigMap可以方便的做到配置解耦,使得不同环境有不同的配置。

  • 保密字典(Secret):Secret是一种加密存储的资源对象,您可以将认证信息、证书、私钥等保存在Secret中,在容器工作负载中作为文件或者环境变量使用,而不需要把这些敏感数据暴露到镜像或者Pod定义中,从而更加安全和灵活。

    Secret与ConfigMap非常像,都是key-value键值对形式,使用方式也相同,不同的是Secret会加密存储,Secret的Value必须使用Base64编码,所以适用于存储敏感信息。

对字符串进行Base64编码,可以直接使用“echo -n 要编码的内容 | base64”命令即 可,示例如下:

  # echo -n "3306" | base64MzMwNg==
  • 存储卷(Persistent Volume,PV):PV指持久化数据存储卷,主要定义的是一个持久化存储在宿主机上的目录,比如一个NFS的挂载目录。

  • 存储卷声明(Persistent Volume Claim,PVC):Kubernetes提供PVC专门用于持久化存储的申请,PVC可以让您无需关心底层存储资源如何创建、释放等动作,而只需要申明您需要何种类型的存储资源、多大的存储空间。

  • 空目录(EmptyDir):EmptyDir是最简单的一种Volume类型,根据名字就能看出,这个Volume挂载后就是一个空目录,应用程序可以在里面读写文件,emptyDir Volume的生命周期与Pod相同,Pod删除后Volume的数据也同时删除掉。emptyDir的一些用途:

    • 缓存空间,例如基于磁盘的归并排序。
    • 为耗时较长的计算任务提供检查点,以便任务能从崩溃前状态恢复执行。

    emptyDir实际是将Volume的内容写在Pod所在节点的磁盘上,另外emptyDir也可以设置存储介质为内存

  • 主机路径(HostPath):HostPath是一种持久化存储,emptyDir里面的内容会随着Pod的删除而消失,但HostPath不会,如果对应的Pod删除,HostPath Volume里面的内容依然存在于节点的目录中,如果后续重新创建Pod并调度到同一个节点,挂载后依然可以读取到之前Pod写的内容。

HostPath存储的内容与节点相关,所以它不适合像数据库这类的应用,如果数据库的Pod被调度到别的节点了,那读取的内容就完全不一样了。

1.5.2. 网络访问场景

工作负载网络访问可以分为如下几种场景:

  • 从集群内部访问工作负载:创建ClusterIP类型的Service,通过Service访问工作负载。

  • 从集群外部访问工作负载:从集群外部访问工作负载推荐使用Service(NodePort类型或LoadBalancer类型)或Ingress访问。

    • 通过公网访问工作负载:需要节点或LoadBalancer绑定公网IP。
    • 通过内网访问工作负载:通过节点或LoadBalancer的内网IP即可访问工作负载。如果跨VPC需要通过对等连接等手段打通不同VPC网络。
  • 工作负载访问外部网络

    • 工作负载访问内网:负载访问内网地址,在不同容器网络模型下有不同的表现,需要注意在对端安全组放通容器网段,具体请参见容器如何访问VPC内部网络。

    • 工作负载访问公网:访问公网有几种方法可以实现,一是让容器所在节点绑定公网IP(容器网络模型为VPC网络或容器隧道网络),或给Pod IP绑定公网IP(云原生2.0网络),另一个是通过NAT网关配置SNAT规则,具体请参见从容器访问公网。

      在这里插入图片描述

1.6. Docker容器典型使用流程

在这里插入图片描述

  • 制作镜像:首先开发者在开发环境机器上开发应用并制作镜像。Docker执行命令,构建镜像并存储在机器上。

  • 上传镜像:开发者发送上传镜像命令。Docker收到命令后,将本地镜像上传到镜像仓库。

  • 运行镜像:开发者向生产环境机器发送运行镜像命令。生产环境机器收到命令后,Docker会从镜像仓库拉取镜像到机器上,然后基于镜像运行容器。

1.7. 常用操作

在这里插入图片描述

接下来本文主要介绍一些常用操作。若想了解更多Docker常用操作命令可以参阅:

  • Download Docker Commands Cheat Sheet
  • Docker技术入门与实战.pdf (访问密码: 6277)
  • 命令参数细节可参阅官方文档Use the Docker command line

1.7.1. 制作DockerFile

常见 Dockerfile 由FROM、RUN、EXPOSE组成,如下

# 使用官方提供的Nginx镜像作为基础镜像
FROM nginx:alpine# 执行一条命令修改Nginx镜像index.html的内容
RUN echo "hello world" > /usr/share/nginx/html/index.html# 允许外界访问容器的80端口
EXPOSE 80
1.7.1.1. Dockerfile命令介绍
1.7.1.1.1. FROM

所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。Dockerfile中FROM是必备的指令,并且必须是第一条指令。

1.7.1.1.2. RUN

RUN 指令是用来执行命令行命令的。由于命令行的强大能力,RUN 指令在定制镜像时是最常用的指令之一。如下为一个正确的写法的Dockerfile。

FROM debian:stretchRUN set -x; buildDeps='gcc libc6-dev make wget' \&& apt-get update \&& apt-get install -y $buildDeps \&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \&& mkdir -p /usr/src/redis \&& tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \&& make -C /usr/src/redis \&& make -C /usr/src/redis install \&& rm -rf /var/lib/apt/lists/* \&& rm redis.tar.gz \&& rm -r /usr/src/redis \&& apt-get purge -y --auto-remove $buildDeps

解读:

  • 这里没有使用很多个RUN一一对应不同的命令,而是仅仅使用一个RUN指令,并使用&&将各个所需命令串联起来,此操作可将7层镜像简化为1层,减少了镜像体积
  • Dockerfile 支持 Shell 类的行尾添加\的命令换行方式,以及行首#进行注释的格式。良好的格式,比如换行、缩进、注释等,会让维护、排障更为容易,这是一个好的习惯
  • 命令的最后添加了清理工作的命令,删除了为了编译构建所需要的软件,清理了所有下载、展开的文件,并且还清理了apt缓存文件。这是很重要的一步,我们之前说过,镜像是多层存储,每一层的东西并不会在下一层被删除,会一直跟随着镜像。因此镜像构建时,一定要确保每一层只添加真正需要添加的东西,任何无关的东西都应该清理掉。
1.7.1.1.3. LABEL

LABEL 指令用来给镜像以键值对的形式添加一些元数据(metadata)
LABEL <key>=<value> <key>=<value> <key>=<value> ...

比如声明镜像的作者,
LABEL author="筑梦之月"

1.7.1.1.4. COPY

COPY [--chown=<user>:<group>] <源路径>... <目标路径>

<源路径> 可以是多个,甚至可以是通配符,其通配符规则要满足 Go 的 filepath.Match (opens new window)规则,如:

COPY hom* /mydir/
COPY hom?.txt /mydir/

<目标路径>可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用WORKDIR指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。

此外,还需要注意一点,使用COPY指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。可在使用该指令的时候还可以加上--chown=<user>:<group>选项来改变文件的所属用户及所属组。

注意: 如果源路径为文件夹,复制的时候不是直接复制该文件夹,而是将文件夹中的内容复制到目标路径。

1.7.1.1.5. ADD

ADD 指令和 COPY 的格式和性质基本一致。但是在COPY基础上增加了一些功能。比如<源路径>可以是一个URL,这种情况下,Docker引擎会试图去下载这个链接的文件放到<目标路径> 去。

如果 <源路径> 为一个tar压缩文件,压缩格式为gzip, bzip2以及xz的情况下,ADD指令将会自动解压缩这个压缩文件到<目标路径> 去。

在Docker官方的Dockerfile最佳实践文档中要求,尽可能的使用COPY,因为COPY的语义很明确,就是复制文件而已,而ADD则包含了更复杂的功能,其行为也不一定很清晰。最适合使用ADD的场合,就是所提及的需要自动解压缩的场合。

1.7.1.1.6. CMD

CMD指令用于执行目标镜像中包含的软件,可以包含参数。指令有以下两种格式:

  • CMD <命令>
  • CMD ["可执行文件", "参数1", "参数2"...]

比如,

  • CMD echo $HOME
  • CMD [ "sh", "-c", "echo $HOME" ]
1.7.1.1.7. ENTRYPOINT

ENTRYPOINT主要用于设置镜像的主命令,允许将镜像当成命令本身来运行(用 CMD 提供默认选项),例如,下面的示例镜像提供了命令行工具ls

ENTRYPOINT ["ls"]CMD ["--help"]

现在直接运行该镜像创建的容器会显示命令帮助,或者提供正确的参数来执行某个命令,比如查看当前容器根目录文件,

$ docker run <镜像ID> /

$ docker run 2c5cdd305083  /
bin
dev
etc
home
lib
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
1.7.1.1.8. WORKDIR

WORKDIR <工作目录路径>

使用WORKDIR指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR会帮你建立目录。

1.7.1.1.9. ENV

这个指令很简单,就是设置环境变量而已,格式有两种:

  • ENV <key> <value>
  • ENV <key1>=<value1> <key2>=<value2>...
1.7.1.1.10. EXPOSE

EXPOSE <端口1> [<端口2>...]

EXPOSE指令是声明容器运行时提供服务的端口,这只是一个声明,在容器运行时并不会因为这个声明应用就会开启这个端口的服务。在Dockerfile 中写入这样的声明有两个好处:

  • 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;
  • 在运行时使用随机端口映射时,也就是docker run -P时,会自动随机映射 EXPOSE 的端口。
1.7.1.1.11. USER

USER <用户名>[:<用户组>]

USER 指令和 WORKDIR 相似,都是改变环境状态并影响以后的层。WORKDIR 是改变工作目录,USER 则是改变之后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。

注意: USER只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。

关于Dockerfile的更多命令介绍请参阅:

  • Docker技术入门与实战.pdf (访问密码: 6277)

  • https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

1.7.2. 构建镜像

执行docker build命令打包镜像,命令格式如下:

docker build -f <dockerfile> -t <name:version> .

比如,
docker build -t hello .
其中-t表示给镜像加一个标签,也就是给镜像取名,这里镜像名为hello。. 表示在当前目录下执行该打包命令。

1.7.3. 查看镜像

执行docker images命令查看镜像。

# docker images
REPOSITORY                   TAG       IMAGE ID       CREATED       SIZE
ghcr.io/scanoss/scanoss-py   latest    2c5cdd305083   2 weeks ago   471MB
owasp/benchmark              latest    7bbf7f60d339   3 weeks ago   2.28GB

1.7.4. 运行镜像

有了镜像后,您可以在本地执行docker run命令运行镜像。命令举例如下,

docker run -it -p 宿主机端口:容器端口 --name 新名字 镜像名:新建并启动容器

参数说明:

-d:后台运行容器(启动便退出,再次进入exit退出后会后台运行),
-i:是以交互模式启动
-t:是为它分配一个伪终端(it经常一起使用)
-p 端口:容器默认端口:指定一个本机端口映射到容器内端口,使得可以从宿主机访问容器内
-P:随机分配映射端口。
-v:宿主机目录(文件):容器目录(文件):文件映射,保持容器文件与外部同步

比如,

# docker run -p 8080:80 hello

此命令会启动一个容器,命令中-p是将本地机器的8080端口映射到容器的80端口,即本地机器的8080端口的流量会映射到容器的80端口。

1.7.5. 上传镜像

上传镜像前需要给镜像取一个完整的名称,如下所示:

docker tag 7bbf7f60d339 owasp/benchmark:1.0

这里,

  • 7bbf7f60d339 是镜像ID
  • 1.0 则是owasp benchmark镜像分配的版本号。

然后执行docker push命令就可以将镜像上传到镜像仓库。

# docker push owasp/benchmark:1.0

1.7.6. 拉取镜像

当需要使用镜像时,使用docker pull命令拉取(下载)该命令即可。

# docker pull owasp/benchmark:1.0

1.7.7. 导入、导出镜像

将镜像保存为镜像库存储文件

docker save -o <镜像库存储文件名> <镜像ID>

将镜像库存储文件导入到镜像库

docker load -i <镜像库存储文件名>

1.7.8. 删除镜像

删除当前镜像

docker rmi <镜像ID>

删除所有不使用的镜像

docker image prune --force --all 或者 docker image prune -f -a

1.7.9. 导出和导入容器

如果要导出本地某个容器生成容器快照,可以使用docker export命令,格式如下

docker export <容器ID>

比如导出如下容器

$ docker container ls -a
CONTAINER ID   IMAGE                        COMMAND                   CREATED       STATUS                       PORTS                    NAMES
d9624b874754   owasp/benchmark              "/bin/bash"               10 days ago   Exited (255) 6 minutes ago   0.0.0.0:8443->8443/tcp   priceless_blackwell$ docker export d9624b874754 > benchmark.tar

可以使用docker import从容器快照文件中再导入为镜像,例如

$ cat ubuntu.tar | docker import - owasp/benchmark:1.0
$ docker image ls
REPOSITORY          TAG             IMAGE ID            CREATED              VIRTUAL SIZE
owasp/benchmark     1.0           7bbf7f60d339        About a minute ago   171.3 MB

保存容器快照时,容器挂载的文件不会保存进镜像,需要分析挂载的路径并拷贝相关数据目录;

注意: 既可以使用docker load来导入镜像存储文件到本地镜像库,也可以使用docker import来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。

1.7.10. 查看容器

列出运行中的容器

docker ps

列出本机所有的容器(包括停止和运行)

docker ps -a

列出所有的容器 ID

docker ps -aq

1.7.10.1. 查看容器详情

docker inspect

1.7.11. 进入、退出容器

进入容器有两种方式:

  • 方式一: docker attach <容器ID>

  • 方式二:docker exec <容器ID>

进入容器通常使用第二种方式,docker exec后面跟的常见参数如下:

-d, --detach 在容器中后台执行命令;

-i, --interactive=true

如果采用方式一,如果从stdin中exit,会导致容器的停止。

1.7.12. 停止容器

停止运行的容器

docker stop <容器ID>

杀死容器进程

docker kill <容器ID>

停止所有的容器

docker stop $(docker ps -aq)

1.7.13. 重启容器

docker restart <容器ID>

1.7.14. 文件复制

从主机复制到容器

docker cp <宿主机路径> <容器ID>:<容器路径>

从容器复制到主机

docker cp <容器ID>:<容器路径> <宿主机路径>

1.7.15. 删除容器

删除单个容器

docker rm <容器ID>

删除所有停止的容器

docker container prune -f

# docker container prune -f
Deleted Containers:
0884f6e6557c2b04e5951f55470dd7975a4975d14c045bf9514ec08eb43877f0
0f78c5a75d5f8f9e2d5b1d003417e47feae8a10cec5e8fe72317d28bdad49db9
665f41f59280753545879e081a1505878008b1056ca988be5f9dfc3b57f8b719
93700e7699dfa48134adec8d36643efab1fb5b15687f432ca8803ad4c21d8077
d9624b87475454cff7753981d6ae9deac47379e41dcab1b720155e2bd92373c3Total reclaimed space: 9.482GB

删除所有停止的容器可以清理磁盘空间,但删除前请确认好,防止重要环境丢失。

1.7.16. 创建一个数据卷

docker volume create <卷名>

1.7.17. 查看数据卷

docker volume ls

$ docker volume ls
DRIVER    VOLUME NAME
local     d9624b87475454cff7753981d6ae9deac47379e41dcab1b720155e2bd92373c3
local     665f41f59280753545879e081a1505878008b1056ca988be5f9dfc3b57f8b719

在主机里使用以下命令可以查看指定数据卷的信息

$ docker volume inspect python
[{"CreatedAt": "2023-04-11T16:18:47+08:00","Driver": "local","Labels": {"dev.container.volume": "true"},"Mountpoint": "/var/lib/containers/storage/volumes/python/_data","Name": "python","Options": {},"Scope": "local"}
]

1.7.18. 删除数据卷

docker volume rm <卷名>

数据卷是被设计用来持久化数据的,它的生命周期独立于容器,Docker不会在容器被删除后自动删除数据卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的数据卷。如果需要在删除容器的同时移除数据卷。可以在删除容器的时候使用docker rm -v这个命令。
无主的数据卷可能会占据很多空间,要清理请使用以下命令

docker volume prune

$ docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
d9624b87475454cff7753981d6ae9deac47379e41dcab1b720155e2bd92373c3
665f41f59280753545879e081a1505878008b1056ca988be5f9dfc3b57f8b719Total reclaimed space: 171kB

1.7.19. 挂载数据卷

1.7.19.1. 默认目录挂载

命令:

docker run [options] -v <任意别名:容器内的路径[:ro | rw]> <镜像名|镜像ID>

解读:

  • 任意别名是一个数据卷名字,名字可以随便写,Docker会在/var/lib/docker/volumes 目录下生成该数据卷(Docker默认的数据卷目录),Podman会在/var/lib/containers/storage/volumes/目录下生成该数据卷(Podman默认的数据卷目录),并且在数据卷里生成_data目录用于与容器目录同步数据;
  • 容器的挂载目录内容覆盖到宿主机的挂载目录内容。

举例:

docker run -d -p 8023:8080 --name tomcat -v tomcat_volume:/usr/local/tomcat/webapps tomcat:latest

tomcat_volume代表一个数据卷名字,可以是任意,这相当于相对路径,它会在/var/lib/docker/volumes/下创建tomcat_volume目录作为数据卷。

1.7.19.2. 具体目录挂载

命令:

docker run [options] -v <宿主机绝对路径 | 任意别名:容器内的路径[:ro | rw]> <镜像名|镜像ID>

解读:

  • 宿主机路径必须是绝对路径,如果目录不存在Docker会自动为你创建它;
  • 宿主机的的挂载目录内容覆盖到容器的挂载目录内容。
1.7.19.3. 匿名目录挂载

命令:
docker run [options] -v <容器内的路径[:ro | rw]> <镜像名|镜像ID>
解读:
没指定名字的挂载都是匿名挂载,-v只写了容器内路径,并没写宿主机路径,这样会在Docker宿主机下/var/lib/docker/volumes/目录中生成匿名数据卷目录。

如执行以下命令

docker run -d -p 3306:3306 --name mysql -v /var/lib/mysql mysql:5.7

可以发现在/var/lib/containers/storage/volumes/目录下自动生成了一串随机字符串组成的匿名数据卷目录d9624b87475454cff7753981d6ae9deac47379e41dcab1b720155e2bd92373c3

$ ls -lh  /var/lib/containers/storage/volumes/
total 4.0K
brw------- 1 root root 8, 32 Apr 11 16:18 backingFsBlockDev
drwx------ 3 root root  4.0K Mar 16 16:45 `d9624b87475454cff7753981d6ae9deac47379e41dcab1b720155e2bd92373c3`

1.7.20. 挂载主机目录

1.7.20.1. 挂载一个主机目录作为数据卷

使用--mount标记可以指定挂载一个本地主机的目录到容器中去。

$ docker run -d -P \--name web \# -v /src/webapp:/usr/share/nginx/html \--mount type=bind,source=/src/webapp,target=/usr/share/nginx/html \nginx:alpine

ro:代表 read-only,容器的路径只允许读,不允许写。不影响宿主机的路径可读可写
rw:默认值,代表可读可写

1.7.20.2. 挂载一个本地主机文件作为数据卷

--mount 标记也可以从主机挂载单个文件到容器中

$ docker run --rm -it -v $HOME/.bash_history:/root/.bash_history \--mount type=bind,source=$HOME/.bash_history,target=/root/.bash_history \ubuntu:20.04 \

2. 最佳实践

2.1. Dockerfile最佳实践

2.1.1. 避免安装不必要的包

为了降低复杂性、减少依赖、减小文件大小、节约构建时间,我们该避免安装任何不必要的包。例如,不要在数据库镜像中包含一个文本编辑器。

2.1.2. 将多行参数排序

将多行参数按字母顺序排序(比如要安装多个包时)。这可以帮助我们避免重复包含同一个包,更新包列表时也更容易。也便于阅读和审查。建议在反斜杠符号\之前添加一个空格,以增加可读性。

下面是buildpack-deps镜像的例子:

RUN apt-get update && apt-get install -y \bzr \cvs \git \mercurial \subversion

2.1.3. 使用多阶段构建

多阶段构建可大幅减小最终镜像的大小,而无须尽力地去想办法减少中间层和文件的数量。镜像是在构建过程的最后阶段构建的,因此可以通过利用构建缓存来最小化镜像层。例如,如果构建包含多个层并且希望确保构建缓存可重用,我们可以将它们从更改频率较低的顺序排列到更改频率较高的顺序。以下列表是指令顺序的示例:

  • 安装构建应用程序所需的工具;
  • 安装或更新库依赖项;
  • 生成应用程序

Go 应用程序的 Dockerfile 样例如下所示:

FROM golang:1.16-alpine AS buildRUN apk add --no-cache git
RUN go get github.com/golang/dep/cmd/dep# List project dependencies with Gopkg.toml and Gopkg.lock
# These layers are only re-built when Gopkg files are updated
COPY Gopkg.lock Gopkg.toml /go/src/project/
WORKDIR /go/src/project/RUN dep ensure -vendor-only# Copy the entire project and build it
# This layer is rebuilt when a file changes in the project directory
COPY . /go/src/project/
RUN go build -o /bin/project# This results in a single layer image
FROM scratch
COPY --from=build /bin/project /bin/project
ENTRYPOINT ["/bin/project"]
CMD ["--help"]

2.2. 镜像加速

执行命令vi /etc/containers/registries.conf,在文件最后添加如下registry

unqualified-search-registries = ["docker.io"][[registry]]
location = "docker.io"[[registry.mirror]]
location = "mirror.baidubce.com"

在cmd窗口执行命令docker info看到如下信息则表明镜像加速配置成功。

registries:docker.io:Blocked: falseLocation: docker.ioMirrorByDigestOnly: false- Insecure: falseLocation: mirror.baidubce.comPullFromMirror: ""Prefix: docker.ioPullFromMirror: ""search:- docker.io

2.3. root方式进入容器

场景:用于执行需要root用户才能执行的操作,比如临时加装软件。

比如普通用户安装vim软件时会提示无权限

$ apt-get install vim
E: Could not open lock file /var/lib/dpkg/lock-frontend - open (13: Permission denied)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), are you root?

在Docker容器中,可以使用--privileged参数让容器拥有宿主机的root权限。
命令如下:

docker run -it --privileged <container id> /bin/bash

Note:如果你没有在启动容器时使用--privileged参数,那么容器中的root用户将不会拥有宿主机的root权限。因此,如果你需要在Docker容器中使用宿主机的root权限,请确保在启动容器时使用了--privileged参数。

3. 参考链接

  • https://support.huaweicloud.com/cce/index.html

  • https://phoenixnap.com/kb/docker-commands-cheat-sheet

  • https://kubernetes.io/zh-cn/docs/home/

  • https://frxcat.fun/pages/90cc29/

  • 镜像的分层结构 - 每天5分钟玩转容器技术(11)

  • Docker技术入门与实战.pdf (访问密码: 6277)

  • https://docs.docker.com/develop/develop-images/dockerfile_best-practices/


在这里插入图片描述

相关文章:

容器技术基础理论与常用命令:必知必会,效率翻倍!

如何利用容器技术提升你的工作效率&#xff1f;掌握基础理论和常用命令是必不可少的&#xff0c;本文将为你全面介绍容器技术&#xff0c;并教你必知必会的技能&#xff0c;让你工作、学习效率翻倍&#xff0c;对于网络安全工作者也是必不可少的技能&#xff01; 0. 引言 学习…...

ChatGPT Edu版本来啦:支持GPT-4o、自定义GPT、数据分析等

5月31日&#xff0c;OpenAI在官网宣布&#xff0c;推出ChatGPT Edu版本。 据悉&#xff0c;这是一个专门为大学校园提供的ChatGTP&#xff0c;支持GPT-4o、网络搜索、自定义GPT、数据分析、代码生成等功能&#xff0c;可以极大提升学生、老师的学习质量和教学效率。 目前&…...

Spark RDD案例

Apache Spark中的RDD&#xff08;Resilient Distributed Dataset&#xff09;是一个不可变、分布式对象集合&#xff0c;它允许用户在大型集群上执行并行操作。虽然RDD在Spark的早期版本中非常核心&#xff0c;但随着DataFrame和Dataset的引入&#xff0c;RDD的使用在某些场景下…...

【线性表 - 数组和矩阵】

数组是一种连续存储线性结构&#xff0c;元素类型相同&#xff0c;大小相等&#xff0c;数组是多维的&#xff0c;通过使用整型索引值来访问他们的元素&#xff0c;数组尺寸不能改变。 知识点数组与矩阵相关题目 # 知识点 数组的优点: 存取速度快 数组的缺点: 事先必须知道…...

Springboot 开发 -- 跨域问题技术详解

一、跨域的概念 跨域访问问题指的是在客户端浏览器中&#xff0c;由于安全策略的限制&#xff0c;不允许从一个源&#xff08;域名、协议、端口&#xff09;直接访问另一个源的资源。当浏览器发起一个跨域请求时&#xff0c;会被浏览器拦截&#xff0c;并阻止数据的传输。 这…...

【Qt】之【项目】整理可参考学习的git项目链接(持续更新)

Tcp 通信相关 IM即时通讯设计 高并发聊天服务&#xff1a;服务器 qt客户端&#xff08;附源码&#xff09; - DeRoy - 博客园 未使用protobuf通讯协议格式 github&#xff1a;GitHub - ADeRoy/chat_room: IM即时通讯设计 高并发聊天服务&#xff1a;服务器 qt客户端 QT编…...

2024年5月个人工作生活总结

本文为 2024年5月工作生活总结。 研发编码 golang 多个defer函数执行顺序 golang 函数中如有多个defer&#xff0c;倒序执行。示例代码&#xff1a; func foo() {defer func() {fmt.Println("111")}()defer func() {fmt.Println("2222")}()defer func()…...

Kafka Java API

1、增加依赖 <dependency><groupId>org.apache.kafka</groupId><artifactId>kafka-clients</artifactId><version>1.0.0</version> </dependency>2、三个案例 案例1&#xff1a;生产数据 import org.apache.kafka.clients.p…...

pushd: not found

解决方法&#xff1a; pushd 比 cd 命令更高效的切换命令&#xff0c;非默认&#xff0c;可在脚本开头添加&#xff1a; #! /bin/bash ubuntu 编译时出现/bin/sh: 1: pushd: not found的问题-CSDN博客...

【第十三节】C++控制台版本坦克大战小游戏

目录 一、游戏简介 1.1 游戏概述 1.2 知识点应用 1.3 实现功能 1.4 开发环境 二、项目设计 2.1 类的设计 2.2 各类功能 三、程序运行截图 3.1 游戏主菜单 3.2 游戏进行中 3.3 双人作战 3.4 编辑地图 一、游戏简介 1.1 游戏概述 本项目是一款基于C语言开发的控制台…...

酷得单片机方案 2.4G儿童遥控漂移车

电子方案开发定制&#xff0c;我们是专业的 东莞酷得智能单片机方案之2.4G遥控玩具童车具有以下比较有特色的特点&#xff1a; 1、内置充电电池&#xff1a;这款小车配备了可充电的电池&#xff0c;无需频繁更换电池&#xff0c;既环保又方便。充电方式可能为USB充电或者专用…...

【为什么 Google Chrome 打开网页有时极慢?尤其是国内网站,如知网等】

要通过知网搜一点资料&#xff0c;发现怎么都打不开。而且B站&#xff0c;知乎这些速度也变慢了&#xff01;已经检查过确定不是网络的问题。 清空了记录&#xff0c;清空了已接受Cookie&#xff0c;清空了缓存内容……没用&#xff01;&#xff01;&#xff01; 不断搜索&am…...

FastAPI - 数据库操作5

先安装mysql驱动程序 pipenv install pymysql安装数据库ORM库SQLAlchemy pipenv install SQLAlchemy修改文件main.py文件内容 设置数据库连接 # -*- coding:utf-8 –*- from fastapi import FastAPIfrom sqlalchemy import create_engineHOST 192.168.123.228 PORT 3306 …...

HTML静态网页成品作业(HTML+CSS)—— 冶金工程专业展望与介绍介绍网页(2个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有2个页面。 二、作品演示 三、代…...

Flutter基础 -- Dart 语言 -- 注释函数表达式

目录 1. 注释 1.1 单行注释 1.2 多行注释 1.3 文档注释 2. 函数 2.1 定义 2.2 可选参数 2.3 可选参数 默认值 2.4 命名参数 默认值 2.5 函数内定义 2.6 Funcation 返回函数对象 2.7 匿名函数 2.8 作用域 3. 操作符 3.1 操作符表 3.2 算术操作符 3.3 相等相关的…...

“仿RabbitMQ实现消息队列”---整体架构与模块说明

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、概念性框架理解 我们主要实现的内容&#xff1a; 1.Broker服务器&#xff1a;消息队列服务器&#xff08;服务端&…...

springboot如何快速接入minio对象存储

1.在项目中添加 Minio 的依赖&#xff0c;在使用 Minio 之前&#xff0c;需要在项目中添加 Minio 的依赖。可以在 Maven 的 pom.xml 文件中添加以下依赖&#xff1a; <dependency><groupId>io.minio</groupId><artifactId>minio</artifactId>&l…...

第六届“智能设计+运维”国产工业软件研讨会暨2024年天洑软件用户大会圆满召开

2024年5月23-24日&#xff0c;第六届“智能设计运维”国产工业软件研讨会暨2024年天洑软件用户大会在南京举办。来自国产工业软件研发企业、制造业企业、高校、科研院所的业内大咖&#xff0c;能源动力、船舶海事、车辆运载、航空航天、新能源汽车、动力电池、消费电子、石油石…...

05.k8s弹性伸缩

5.k8s弹性伸缩 k8s弹性伸缩,需要附加插件heapster监控 弹性伸缩&#xff1a;随着业务访问量的大小&#xff0c;k8s系统中的pod比较弹性&#xff0c;会自动增加或者减少pod数量&#xff1b; 5.1 安装heapster监控 1:上传并导入镜像,打标签 ls *.tar.gz for n in ls *.tar.gz…...

【数据结构】详解二叉树

文章目录 1.树的结构及概念1.1树的概念1.2树的相关结构概念1.3树的表示1.4树在实际中的应用 2.二叉树的结构及概念2.1二叉树的概念2.2特殊的二叉树2.2.1满二叉树2.2.2完全二叉树 2.3 二叉树的性质2.4二叉树的存储结构2.4.1顺序结构2.4.2链表结构 1.树的结构及概念 1.1树的概念…...

MapDB:轻量级、高性能的Java嵌入式数据库引擎

MapDB&#xff1a;轻量级、高性能的Java嵌入式数据库引擎 在今天的软件开发中&#xff0c;嵌入式数据库因其轻便、高效和易于集成而备受欢迎。对于Java开发者来说&#xff0c;MapDB无疑是一个值得关注的选项。MapDB是一个纯Java编写的嵌入式数据库引擎&#xff0c;它提供了高性…...

Rye: 一个革新的Python包管理工具

文章目录 Rye: 一个革新的Python包管理工具Rye的诞生背景Rye的核心特性Rye的安装与使用Rye的优势与挑战Rye的未来展望结语 Rye: 一个革新的Python包管理工具 在Python生态系统中&#xff0c;包管理一直是一个复杂且令人头疼的问题。随着Python社区的不断发展&#xff0c;出现了…...

如何在C#代码中判断当前C#的版本和dotnet版本

代码如下&#xff1a; using System.Reflection; using System.Runtime.InteropServices;var csharpVersion typeof(string).Assembly.GetCustomAttributes(typeof(AssemblyFileVersionAttribute), false).OfType<AssemblyFileVersionAttribute>().FirstOrDefault()?.…...

Linux 36.3@Jetson Orin Nano之系统安装

Linux 36.3Jetson Orin Nano之系统安装 1. 源由2. 命令行烧录Step 1&#xff1a;下载Linux 36.3安装程序Step 2&#xff1a;下载Linux 36.3根文件系统Step 3&#xff1a;解压Linux 36.3安装程序Step 4&#xff1a;解压Linux 36.3根文件系统Step 5&#xff1a;安装应用程序Step …...

案例实践 | 基于长安链的首钢供应链金融科技服务平台

案例名称-首钢供应链金融科技服务平台 ■ 建设单位 首惠产业金融服务集团有限公司 ■ 用户群体 核心企业、资金方&#xff08;多为银行&#xff09;等合作方 ■ 应用成效 三大业务场景&#xff0c;共计关联29个业务节点&#xff0c;覆盖京票项目全部关键业务 案例背景…...

Vue3实战笔记(55)—Vue3.4新特性揭秘:defineModel重塑v-model,拥抱高效双向数据流!

文章目录 前言defineModel() 基本用法总结 前言 v-model 可以在组件上使用以实现双向绑定。 从 Vue 3.4 开始&#xff0c;推荐的实现方式是使用 defineModel() 宏 defineModel() 基本用法 定义defineModel()&#xff1a; <!-- Child.vue --> <script setup> con…...

C++ | Leetcode C++题解之第123题买卖股票的最佳时机III

题目&#xff1a; 题解&#xff1a; class Solution { public:int maxProfit(vector<int>& prices) {int n prices.size();int buy1 -prices[0], sell1 0;int buy2 -prices[0], sell2 0;for (int i 1; i < n; i) {buy1 max(buy1, -prices[i]);sell1 max(…...

微信小程序中Button组件的属性值和用法详解

在微信小程序开发中&#xff0c;Button组件是非常常用的UI组件之一&#xff0c;它可以让用户进行交互操作&#xff0c;比如提交表单、跳转页面等。了解Button组件的属性值和用法对于开发者来说至关重要。 1. Button组件简介 简要介绍Button组件在小程序中的作用和重要性&…...

等保测评 | 等保测评简介及流程具体是什么?

等保测评是指对信息系统进行安全性评估和测试&#xff0c;以确保其符合国家相关等级保护要求。在当前信息时代&#xff0c;各类机构和企业面临着日益严峻的网络安全风险&#xff0c;等保测评成为了保障信息系统安全的重要手段之一。本文将介绍等保测评的基本概念、流程和重要性…...

CompassArena 司南大模型测评--代码编写

测试角度 要说测试模型&#xff0c;对咱们程序员来说&#xff0c;那自然是写代码的能力强不强比较重要了。那么下面我们以 leetcode 中的一道表面上是困难题的题目来考考各家大模型&#xff0c;看看哪个才应该是咱们日常写程序的帮手。 部分模型回答 问题部分如下截图&#…...

叉积和法向量学习笔记

目录 叉积用的内积 相似点 给定平面上的两个向量 A 和 B&#xff0c;叉积和法向量相等吗 理解这点的关键&#xff1a; 结论&#xff1a; 叉积判断平面内两个向量是否相交 叉积&#xff08;Cross Product&#xff09;和法向量&#xff08;Normal Vector&#xff09;确实有…...

YZW900规格书

title: “深圳市沃进科技有限公司” 深圳市沃进科技有限公司 TOP视图 特性 异地组网&#xff0c;远程访问有线/无线备份单模双卡备份5G转有线&#xff0c;5G转WIFI2.4G5.8G双频WIFI三网口&#xff0c;WAN/LAN可切换软硬件看门狗智能防掉线云平台、客户端远程管理安装支架安装铝…...

9岁学生学什么编程好一些:探索编程启蒙的奥秘

9岁学生学什么编程好一些&#xff1a;探索编程启蒙的奥秘 在数字时代&#xff0c;编程已逐渐成为一项基本技能。对于9岁的学生来说&#xff0c;选择适合的编程课程或平台&#xff0c;对于培养逻辑思维、创新思维以及解决问题的能力至关重要。那么&#xff0c;9岁学生学什么编程…...

Java反射实战指南:反射机制的终极指南

1. 反射机制简介 在Java中&#xff0c;反射机制提供了一种强大的工具&#xff0c;用于在运行时检查类、接口、字段和方法。但它的重要性不止于此&#xff0c;它允许程序动态加载、探索和使用编译时完全未知的代码。这种能力是Java语言支持的一种“动态”特性&#xff0c;使得J…...

高效训练超越LoRA,北航发布MoRA

什么&#xff01;LoRA我都没有学懂&#xff0c;又出现了MoRA&#xff1f;&#xff1f;&#xff1f; LoRA作为当下最火热的大语言模型参数高效微调技术&#xff0c;正在以前所未有的速度迭代更新。从最初的LoRA到陆续推出的LoRA、DoRA、AsyLoRA等变体&#xff0c;LoRA家族可谓是…...

【Spring】Spring之依赖注入源码解析(上)

目录 Spring中到底有几种依赖注入的方式&#xff1f; 手动注入 自动注入 XML的autowire自动注入 Autowired注解的自动注入 寻找注入点 桥接方法 注入点进行注入 字段注入 Set方法注入 Spring中到底有几种依赖注入的方式&#xff1f; 首先分两种&#xff1a; 手动注…...

HBase 常用 shell 操作

下面给大家介绍一些HBase 常用 shell 操作&#xff0c;各位看官看好了啦&#xff0c;我要献丑了。 进入 HBase 客户端命令操作界面 $ bin/hbase shell查看帮助命令 > help查看当前数据库中有哪些表 > list创建一张表 创建 user 表&#xff0c;包含 info、data 两个列…...

【区分vue2和vue3下的element UI InputNumber 计数器组件,分别详细介绍属性,事件,方法如何使用,并举例】

在 Vue 2 中&#xff0c;Element UI 提供了 el-input-number 组件作为计数器组件&#xff0c;用于处理数字输入。而在 Vue 3 中&#xff0c;Element Plus 同样提供了类似的组件&#xff0c;但可能有一些属性、事件或方法的细微差异。下面我将分别介绍 Vue 2 的 Element UI 和 V…...

科普健康短视频:成都鼎茂宏升文化传媒公司

科普健康短视频&#xff1a;引领健康知识新潮流 在数字化时代的浪潮中&#xff0c;短视频以其短小精悍、直观易懂的特点&#xff0c;迅速成为大众获取信息的重要渠道。其中&#xff0c;科普健康短视频更是凭借其科学、权威、实用的内容&#xff0c;吸引了大量关注健康的观众。…...

Amis源码构建 sdk版本

建议在linux环境下构建&#xff08;mac环境下也可以&#xff09;&#xff0c;需要用到sh脚本&#xff08;amis/build.sh&#xff09;。 Js sdk打包是基于fis进行编译打包的&#xff0c;具体可见fis-conf.js&#xff1a; amis-master源码下载:https://github.com/baidu/amis g…...

【MySQL数据库】:MySQL复合查询

目录 基本查询回顾 多表查询 自连接 子查询 单行子查询 多行子查询 多列子查询 在from子句中使用子查询 合并查询 前面我们讲解的mysql表的查询都是对一张表进行查询&#xff0c;在实际开发中这远远不够。 基本查询回顾 【MySQL数据库】&#xff1a;MySQL基本查…...

PS Mac Photoshop 2024 for Mac[破]图像处理软件[解]PS 2024安装教程[版]

Mac分享吧 文章目录 效果一、准备工作二、开始安装1、Anticc简化版安装1.1双击运行软件&#xff0c;安装1.2 解决来源身份不明的开发者问题**此代码为打开&#xff1a;系统偏好设置 – 隐私与安全性&#xff0c;中的【任何来源】&#xff0c;如下图&#xff1a;**1.3 再次运行…...

深入URP之Shader篇16: UNITY_BRANCH和UNITY_FLATTEN

Shader中的if分支 我们在shader中写if语句&#xff0c;例如&#xff1a; if(a>0){//do some cool thing }else{//do other cool thing }实际上&#xff0c;编译器会进行优化&#xff0c;以及处理成多种不同的情况。比如编译器会将if和else展开&#xff0c;分别执行其中的代…...

5.25.1 用于组织病理学图像分类的深度注意力特征学习

提出了一种基于深度学习的组织病理学图像分类新方法。我们的方法建立在标准卷积神经网络 (CNN) 的基础上,并结合了两个独立的注意力模块,以实现更有效的特征学习。 具体而言,注意力模块沿不同维度推断注意力图,这有助于将 CNN 聚焦于关键图像区域,并突出显示判别性特征通…...

uni-app+php 生成微信二维码 分销海报

主要代码如下&#xff0c;可直接复制调试参数&#xff1a; //查询当前用户是否有分销海报public function user_poster(){$this->checkAuth();//查询会员信息$user $this->getUserInfoById($this->user_id);if(!empty($user[distribution_img])){$result[data] $use…...

已解决java.lang.annotation.AnnotationFormatError: 注解格式错误的正确解决方法,亲测有效!!!

已解决java.lang.annotation.AnnotationFormatError: 注解格式错误的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 亲测有效 报错问题解决思路 解决方法解决方法1. 检查注解定义2. 验证注解使用位置3. 检查注解参数4. 更新依赖库5. 示例代码 解决思路…...

使用 EBS 和构建数据库服务器并使用应用程序与数据库交互

实验 4&#xff1a;使用 EBS 实验概览 本实验着重介绍 Amazon Elastic Block Store (Amazon EBS)&#xff0c;这是一种适用于 Amazon EC2 实例的重要底层存储机制。在本实验中&#xff0c;您将学习如何创建 Amazon EBS 卷、将其附加到实例、向卷应用文件系统&#xff0c;然后进…...

pom文件新增依赖时异常问题定位技巧

今天新增复制两个依赖到项目时&#xff0c;莫名其妙一个爆红artifactId和version&#xff0c;另一个爆红version&#xff0c;但放其他项目却正常&#xff0c;非常莫名其妙。经过一番折腾&#xff0c;终于发现不知道什么时候不小心多写了一个单独的导致的&#xff0c;但是这个异…...

【小白专用24.5.30已验证】Composer安装php框架thinkPHP6的安装教程

一、框架介绍 1、框架简介和版本选择 Thinkphp是一种基于php的开源web应用程序开发框架ThinkPHP框架&#xff0c;是免费开源的、轻量级的、简单快速且敏捷的php框架。你可以免费使用TP框架&#xff0c;甚至可以将你的项目商用&#xff1b; ThinkPHP8.0 是目前框架正式版的最新版…...

ch4网络层---计算机网络期末复习(持续更新中)

网络层概述 将分组从发送方主机传送到接收方主机 发送方将运输层数据段封装成分组 接收方将分组解封装后将数据段递交给运输层网络层协议存在于每台主机和路由器上 路由器检查所有经过它的IP分组的分组头 注意路由器只有3层(网络层、链路层、物理层) 网络层提供的服务 一…...