Docker是一个跨平台、可移植并且简单易用的容器解决方案。基于Go语言开发。Docker可在容器内部快速自动化地部署应用,并通过操作系统内核技术(namespaces、cgroup等)为容器提供资源隔离和安全保障。
containerd是一个工业级标准的容器运行时,可以在宿主机中管理完整的容器生命周期:容器镜像的传输和存储、容器的执行和管理、存储和网络等。containerd是从docker中分离出来的,或者说containerd本身是docker的一部分。
containerd并不是直接面向最终用户的,而是主要用于集成到更上层的系统里,比如Swarm,Kubernetes,Mesos等容器编排系统。containerd以Daemon的形式运行在系统上,通过unixdomainsocket暴露很底层的gRPCAPI,上层系统可以通过这些API管理机器上的容器。每个containerd只负责一台机器,Pull镜像,对容器的操作(启动、停止等),网络,存储都是由containerd完成。具体运行容器由runC负责,实际上只要是符合OCI规范的容器都可以支持。
一方面应用包含多种服务,这些服务有自己所依赖的库和软件包;另一方面存在多种部署环境,服务在运行时可能需要动态迁移到不同环境中。这就产生了一个问题:如何让每种服务能够在所有的部署环境中顺利进行?各种服务与环境排列组合产生了一个大矩阵,开发人员需要考虑不同的运行环境,运维人员需要为不同的服务和平台配置环境。这对双方而言,都是一项艰难的任务。如何解决这个问题呢?
最终程序员们从传统运输业找到了答案。
集装箱的发明解决这个难题。任何货物,无论钢琴还是保时捷,都被放到各自的集装箱中。集装箱在整个运输过程中都是密封的,只有到达最终目的地才被打开。标准集装箱可以被高效地装卸、重叠和长途运输。现代化的起重机可以自动在卡车、轮船和火车之间移动集装箱。集装箱被誉为运输业与世界贸易最重要的发明。
Docker将集装箱思想运用到软件打包上,为代码提供了一个基于容器的标准化运输系统。Docker可以将任何应用及其依赖打包成一个轻量级、可移植、自包含的容器。容器可以运行在几乎所有的操作系统上。
镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,DockerRegistry就是这样的服务。
一个DockerRegistry中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。
通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过仓库名:标签的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以latest作为默认标签。
以Ubuntu镜像为例,ubuntu是仓库的名字,其内包含有不同的版本标签,如,16.04,18.04。我们可以通过ubuntu:16.04,或者ubuntu:18.04来具体指定所需哪个版本的镜像。如果忽略了标签,比如ubuntu,那将视为ubuntu:latest
Docker的镜像概念类似于虚拟机里的镜像,是一个只读的模板,一个独立的文件系统,包括运行容器所需的数据,可以用来创建新的容器。docker镜像是一个只读的docker容器模板,它含有启动docker容器所需的文件系统结构及内容,是启动一个docker容器的基础。镜像(Image)是Docker最突出的创新。
镜像是容器的基础,每次执行dockerrun的时候都会指定哪个镜像作为容器运行的基础。
docker镜像的文件内容以及一些运行docker容器的配置文件组成了docker容器的静态文件系统运行环境———rootfs。
rootfs是docker容器在启动时内部进程可见的文件系统,即docker容器的根目录。rootfs通常包含一个操作系统运行时所需的文件系统。
在传统的linux操作系统内核启动时,首先挂载一个只读的rootfs,当系统检测其完整性以后,再将其切换为读写模式。在dockerdaemon为docker容器挂载rootfs时,沿用了上述方法,即将rootfs设为只读模式,挂载完毕后,利用联合挂载(unionmount)技术在已有的只读rootfs上在挂载一个读写层。
镜像的特点:分层:docker镜像是采用分层方式构建的,每个镜像都由一系列的“镜像层”组成写时复制:每个容器启动时不需要单独复制一份镜像文件,而是将所有镜像层以只读的方式挂载到一个挂载点,在其上覆盖一个可读写的容器层。内容寻址:对镜像内容计算校验和,生成内容哈希,减少冲突。联合挂载:联合挂载技术可以在一个挂载点同时挂载多个文件系统,将挂载点的原目录与被挂载的内容进行整合,使得最终可见的文件系统将会包含整合之后的各层的文件和目录。
将一个镜像导出为tar文件再解压后,其中的文件如下
$dockersave-ohello-world.tarhello-world:latest$tar-xvfhello-world.tar-Chello-world-imagecdccdf50922d90e847e097347de49119be0f17c18b4a2d98da9919fa5884479d/cdccdf50922d90e847e097347de49119be0f17c18b4a2d98da9919fa5884479d/VERSIONcdccdf50922d90e847e097347de49119be0f17c18b4a2d98da9919fa5884479d/jsoncdccdf50922d90e847e097347de49119be0f17c18b4a2d98da9919fa5884479d/layer.tarfce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e.jsonmanifest.jsonrepositories1、manifest.json清单(manifest)文件是一段元数据,描述了该镜像中的内容。
3、此外有好多子目录,每个子目录是文件系统的一层(layer),每个子目录里也有一个json描述当前层的元数据信息。
镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。容器是一个运行的镜像实例,可以创建、启动、终止、删除它。一个容器可以连接多个网络和存储。删除容器后,任何未在存储中进行的修改都会消失。可以这样理解,dockerimage是dockercontainer的静态视角,dockercontainer是dockerimage的运行方式。
UnionFileSystem,简称UnionFS,是一种为Linux,FreeBSD,和NetBSD操作系统设计的把其他文件系统联合挂载到一个挂载点的文件系统服务。它通过使用branch把不同文件系统的文件和目录覆盖,形成一个一致的文件系统。这些branch是只读或者只写的。当对文件进行写操作时候,才会真正的复制文件进行写操作。实际上本身没有对原来的文件进行修改,可以看做是共享了原来的文件。在写的时候进行修改用到了一种资源管理技术成为写时复制。
联合文件系统(UnionFileSystem):2004年由纽约州立大学石溪分校开发,它可以把多个目录(也叫分支)内容联合挂载到同一个目录下,而目录的物理位置是分开的。UnionFS允许只读和可读写目录并存,就是说可同时删除和增加内容。UnionFS应用的地方很多,比如在多个磁盘分区上合并不同文件系统的主目录,或把几张CD光盘合并成一个统一的光盘目录(归档)。另外,具有写时复制(copy-on-write)功能UnionFS可以把只读和可读写文件系统合并在一起,虚拟上允许只读文件系统的修改可以保存到可写文件系统当中。
Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(uniteseveraldirectoriesintoasinglevirtualfilesystem)。
AUFS的英文全称为AdvancedMult-LayeredUnificationFilesystem,之前叫AnotherMult-LayeredUnificationFilesystem
AUFS(AnotherUnionFS)就是一种UnionFS。AUFS支持为每一个成员目录(类似Git的分支)设定只读(readonly)、读写(readwrite)和写出(whiteout-able)权限,同时AUFS里有一个类似分层的概念,对只读权限的分支可以逻辑上进行增量地修改(不影响只读部分的)。
OverlayFS是和AUFS相似的联合文件系统(unionfilesystem),它有如下特点:设计简洁;内核3.18开始已经并入内核主线可能更快
OverlayFS将单个Linux主机上的两个目录进行分层,然后将它们表示为一个目录。这些目录就叫做layers,这个过程就被叫做unionmount。OverlayFS将靠下一层的目录叫做lowerdir,将靠上一层的叫做upperdir。然后经过处理后我们看到的那个目录叫做merged。
Linux各发行版实现的UnionFS各不相同,所以Docker在不同linux发行版中使用的UFS也不同。Docker支持几种不同的UFS实现,包括AUFS、Overlay、devicemapper、BTRFS和ZFS。哪一个被用看系统需要并且可以通过运行dockerinfo来检查,在“StorageDriver”下列出:
$dockerinfo|grep"Storage"StorageDriver:overlay2初代docker默认的存储驱动是AUFS,后来docker默认的存储驱动已经演进到了overlay2
每个容器都有它们自己的文件系统视图,Docker获取镜像所有的层,并使它们层叠在一起,以呈现为文件系统的一个视图。这个技术称为UnionMounting,Docker支持Linux上的几个UnionMount文件系统,主要是OverlayFS和AUFS。
Docker的文件系统是如何工作的?Docker镜像是由多个文件系统(只读层)叠加而成。当我们启动一个容器的时候,Docker会加载只读镜像层并在其上(译者注:镜像栈顶部)添加一个读写层。如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏。当删除Docker容器,并通过该镜像重新启动时,之前的更改将会丢失。在Docker中,只读层及在顶部的读写层的组合被称为UnionFileSystem(联合文件系统)。
Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
另外,不同Docker容器就可以共享一些基础的文件系统层,同时再加上自己独有的改动层,大大提高了存储的效率。
为了能够保存(持久化)数据以及共享容器间的数据,Docker提出了Volume的概念。简单来说,Volume就是目录或者文件,它可以绕过默认的联合文件系统,而以正常的文件或者目录的形式存在于宿主机上。
如果多个容器共享同一个基础镜像,基础镜像被修改,例如/etc/修改,是否会影响?答案是不会容器其实是在镜像的最上面加了一层读写层,在运行容器里文件改动时,会先从镜像里要写的文件复制到容器自己的文件系统中(读写层)。如果容器删除了,最上面的读写层也就删除了,改动也就丢失了。所以无论多少个容器共享一个镜像,所做的写操作都是从镜像的文件系统中复制过来操作的,并不会修改镜像的源文件,这种方式提高磁盘利用率。若想持久化这些改动,可以通过dockercommit将容器保存成新的镜像
volume在容器创建时就会初始化,所以运行时就可以使用。在不同容器间共享和重用。对volume中数据的操作会马上生效。对volume中的数据操作不会影响到镜像本身。volume的生存周期独立于容器的生存周期,即使删除容器,volume依然存在,没有任何容器使用它,也不会被docker删除。
按照Docker最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。
数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。
数据卷是被设计用来持久化数据的,它的生命周期独立于容器,Docker不会在容器被删除后自动删除数据卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的数据卷。如果需要在删除容器的同时移除数据卷。可以在删除容器的时候使用dockerrm-v这个命令。
Docker在运行时分为Docker引擎(也就是服务端守护进程)和客户端工具。Docker的引擎提供了一组RESTAPI,被称为DockerRemoteAPI,而如docker命令这样的客户端工具,则是通过这组API与Docker引擎交互,从而完成各种功能。因此,虽然表面上我们好像是在本机执行各种docker功能,但实际上,一切都是使用的远程调用形式在服务端(Docker引擎)完成。也因为这种C/S设计,让我们操作远程服务器的Docker引擎变得轻而易举。
dockerdaemon接受dockerapi的请求,并管理docker中定义的对象:镜像、容器、网络、数据卷等。dockerclient是大多数人与docker打交道的工具,比如当你输入dockerrun命令时,dockerclient将命令发到daemon执行。
安装Docker时,它会自动创建3个网络。可以使用dockernetworkls命令列出这些网络。这3个网络包含在Docker实现中。运行一个容器时,可以使用--net标志指定您希望在哪个网络上运行该容器。您仍然可以使用这3个网络。
bridge网络表示所有Docker安装中都存在的docker0网络。除非使用dockerrun--net=
bridge即桥接网络,以桥接模式连接到宿主机,即宿主机和容器之间通过docker0虚拟网卡连到同一个局域网。bridge是默认的网络模式host宿主网络,即与宿主机共用网络,这种模式相当于没有网络隔离,好处是和宿主机处于同一网络,可随意访问,都不用-p做端口映射了。none则表示无网络,容器将无法联网
overlay跨主机网络。在早期的docker版本中,是不支持跨主机通信网络驱动的,也就是说明如果容器部署在不同的节点上面,只能通过暴露端口到宿主机上,再通过宿主机之间进行通信。docker1.9之后,随着dockerswarm集群的推广,docker也有了自家的跨主机通信网络驱动,名叫overlay,overlay网络模型是swarm集群容器间通信的载体,将服务加入到同一个网段上的Overlay网络上,服务与服务之间就能够通信。
安装Docker的时候,会在宿主机安装一个虚拟网卡docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。
$ifconfigdocker0:flags=4163
host网络和主机之间没有隔离,和主机共享一个networknamespace.
注意:使用host网络模式时,端口映射不起作用。dockerrun时的-p,--publish,-P,--publish-all参数会被忽略,并产生一条警告:WARNING:Publishedportsarediscardedwhenusinghostnetworkmode
host类型网络只能在Linux上使用,在Mac和Windows上不支持。ThehostnetworkingdriveronlyworksonLinuxhosts,andisnotsupportedonDockerDesktopforMac,DockerDesktopforWindows,orDockerEEforWindowsServer.
1、容器内访问宿主机使用docker.for.mac.host.internal或者host.docker.internal这两个特定域名可访问宿主机,这是docker容器内配置好的可解析到宿主机IP的DNS,可以直接当宿主机的IP使用。进入任意容器后,ping这两个域名都会解析到宿主机IP
2、宿主机访问容器通过-p端口映射。例如dockerrun-p8081:80-dnginx之后在主机上通过localhost:8081可直接访问容器内的80端口
docker-proxy是dockerd的子进程,用于端口映射。docker-proxy主要是用来做端口映射的。当我们使用dockerrun命令启动容器时,如果使用了-p参数,docker-proxy组件就会把容器内相应的端口映射到主机上来,底层是依赖于iptables实现的。
1、netstat-anp查看端口占用看到是docker-proxy进程,获取pid2、ps-ef|greppid查看进程命令,看到是监听宿主机8080端口转发到192.168.42.2容器的8080端口
root75958119310Aug2100:00:00/usr/local/bin/docker-proxy-prototcp-host-ip0.0.0.0-host-port8080-container-ip192.168.42.2-container-port80803、dockerps|grep8080端口,能看到是哪个容器在使用8080端口4、dockerinspectcontainer-id|grepIPAddress能看到使用8080端口的容器的ip就是192.168.42.2
chroot隔离文件系统namespace隔离进程访问cgroups隔离资源使用
docker并不是彻底的虚拟化,不同容器之间会共享内核。Linux虚拟机是完全的虚拟化,内核隔离。
LinuxCGroup全称LinuxControlGroup,是Linux内核的一个功能,用来限制,控制与分离一个进程组群的资源(如CPU、内存、磁盘输入输出等)CGroup主要提供了如下功能:Resourcelimitation:限制资源使用,比如内存使用上限以及文件系统的缓存限制。Prioritization:优先级控制,比如:CPU利用和磁盘IO吞吐。Accounting:一些审计或一些统计,主要目的是为了计费。Control:挂起进程,恢复执行进程。
容器request/limit利用cgroupcpu公平调度器实现。
Docker只能安装在64位机器上。
前提条件:1安装DockerEngine-Community需要CentOS7版本及以上,老版本不支持。2需要开启centos-extrasyumrepo,默认是开启的。
1安装yum仓库管理工具yum-utils,以及device-mapper-persistent-data,lvm2
$sudoyuminstall-yyum-utils\device-mapper-persistent-data\lvm22安装dockerrepo
sudoyuminstalldocker-cedocker-ce-clicontainerd.io我安装的版本信息
sudosystemctlrestartdocker容器会全部停止,之后需要重启容器
停止docker服务systemctlstopdocker
查看当前版本rpm-qa|grepdocker
#rpm-qa|grepdockernvidia-container-runtime-2.0.0-1.docker17.06.2.x86_64docker-ce-17.06.2.ce-1.el7.centos.x86_64nvidia-docker2-2.0.3-1.docker17.06.2.ce.noarch删除当前版本yumremovedocker-ce-17.06.2.ce-1.el7.centos.x86_64
DockerDesktopforMac要求系统最低为2010年以后的Mac机型,准确说是带IntelMMU虚拟化的,macOS10.13及以上版本,最低4GB内存。如果不满足已上要求,可以使用DockerToolbox安装Docker来代替DockerDesktop,DockerToolbox使用OracleVirtualBox虚拟机而不是HyperKit虚拟机。
Homebrew的Cask已经支持DockerDesktopforMac,因此可以很方便的使用HomebrewCask来进行安装:brewinstall--caskdocker
查看docker版本docker--version
$docker--versionDockerversion19.03.5,build633a0ea启动一个nginx验证dockerrun-d-p80:80--namenginx--rmnginx
Dockerfile是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
定制镜像必须以一个镜像为基础,在其上进行定制。FROM指定基础镜像,因此一个Dockerfile中FROM是必备的指令,并且必须是第一条指令。Docker还存在一个特殊的镜像,名为scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。
VOLUME在镜像中创建挂载点VOLUME后的目录格式可以是纯文本的目录,空格分割的多个目录,或者json格式的字符串数组
VOLUME/var/logVOLUME/var/log/var/dbVOLUME["/data1","/data2"]相比于dockerrun时-v指定目录映射,VOLUME指令可实现通过此镜像创建的容器内都有一个预先创建好的目录,当然使用dockerrun-v也完全可以代替VOLUME指令。
ADD指令和COPY的格式和性质基本一致。但是在COPY基础上增加了一些功能。比如源路径可以是一个URL,这种情况下,Docker引擎会试图去下载这个链接的文件放到目标路径去。下载后的文件权限自动设置为600,如果这并不是想要的权限,那么还需要增加额外的一层RUN进行权限调整,另外,如果下载的是个压缩包,需要解压缩,也一样还需要额外的一层RUN指令进行解压缩。所以不如直接使用RUN指令,然后使用wget或者curl工具下载,处理权限、解压缩、然后清理无用文件更合理。因此,这个功能其实并不实用,而且不推荐使用。
相比COPY,ADD其实就增加了2个特性:1、ADD指令可以让你使用URL作为src参数。当遇到URL时候,可以通过URL下载文件并且复制到dest2、ADD的另外一个特性是有能力自动解压文件。如果src参数是一个可识别的压缩格式(tar,gzip,bzip2,etc)的本地文件(所以实现不了同时下载并解压),就会被解压到指定容器文件系统的路径dest
WORKDIR<工作目录路径>使用WORKDIR指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR会帮你建立目录
RUN指令是用来执行命令行命令的,通常用于安装应用和软件包。Dockerfile中每一个指令都会建立一层,RUN也不例外。每一个RUN的行为,就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束后,commit这一层的修改,构成新的镜像。
例如
RUNapkadd--no-cachetzdata\&&ln-sf/usr/share/zoneinfo/Asia/Shanghai/etc/localtime\&&echo"Asia/shanghai">/etc/timezone\&&rm-rf/var/cache/apk/*/tmp/*/var/tmp/*$HOME/.cache##清除缓存RUNchmod+x/root/apps/start_jar.sh第一个安装时区的多条命令放在一个RUN中,保证构建在同一层镜像
CMD指令用于指定默认的容器主进程的启动命令的,此命令会在容器启动且dockerrun没有指定其他命令时运行,如果dockerrun后面指定其他命令则CMD会被忽略在运行时可以指定新的命令来替代镜像设置中的这个默认命令Dockerfile中可以有多个CMD指令,但只有最后一个生效
例如CMDecho"Helloworld"运行容器dockerrun-it[image]将输出Helloworld,但当后面加上一个命令,比如dockerrun-it[image]/bin/bash,CMD会被忽略掉,命令bash将被执行,会进入容器。
ENTRYPOINT用于设置容器启动时要执行的命令及其参数,当指定了ENTRYPOINT后,CMD的含义就发生了改变,不再是直接的运行其命令,而是将CMD的内容作为参数传给ENTRYPOINT指令,换句话说实际执行时,将变为:
RUN命令会创建新的镜像层,通常用于安装应用和软件包。Dockerfile中常常包含多个RUN指令,每条RUN指令都会生成新的一层。CMD和ENTRYPOINT都可用于设置容器的启动命令,CMD会被dockerrun命令覆盖,而ENTRYPOINT不会,dockerrun命令中的参数都会成为ENTRYPOINT的参数。
ENTRYPOINT["/usr/bin/rethinkdb"]CMD["--help"]这个dockerfile里ENTRYPOINT后面还有个CMD的考虑是,如果dockerrun没有参数,CMD(–help)将成为ENTRYPOINT的默认参数,输出帮助信息,例如dockerrunrethinkdb时就会输出帮助信息。当dockerrun有参数时会代替CMD命令,例如dockerrun-itrethinkdbbash可以进入容器。
RUN/CMD/ENTRYPOINT命令的格式有两种:1、shell格式RUN/CMD/ENTRYPOINT<命令>就像直接在命令行中输入的命令一样。例如
指定运行容器时的用户名或UID,后续的RUN等指令也会使用指定的用户身份使用USER指定用户时,可以使用用户名、UID或GID,或是两者的组合使用USER指定用户后,Dockerfile中后续的命令RUN、CMD、ENTRYPOINT都将使用该用户
也可以使用dockerrun-u指定用户
FROMiregistry.baidu-int.com/baidu-base/golang:1.19-alpine3.16ASbuilderCOPY--from=builder/app/bin//app/bin/二、dockerexport/import镜像导出再导入可压缩镜像
dockersystemdf查看docker磁盘占用汇总信息
dockersystemdfTYPETOTALACTIVESIZERECLAIMABLEImages43342117.4GB97.11GB(82%)Containers103892.145GB1.464GB(68%)LocalVolumes96116B58B(50%)BuildCache000B0BRECLAIMABLE是空闲镜像(没有任何容器使用的镜像)的大小,空闲镜像可以用命令dockerimageprune-a清理
dockersystemdf加-v参数显示详细的磁盘占用信息,能看到每个镜像、容器、卷的磁盘占用情况:
2、进入containers子目录,里面每个容器对应一个目录,目录名是容器ID,dockerps结果的第一列就是容器ID的前缀每个容器目录中有容器ID-json.log的日志文件,通常会比较大,可以直接>contain-id-json.log清理掉
新建或修改docker配置/etc/docker/daemon.json
34Me5e0fbde1e9b3ef24bef5228e2381936568f97d7da5b7214f3883f40bc32c809-json.log48Me5e0fbde1e9b3ef24bef5228e2381936568f97d7da5b7214f3883f40bc32c809-json.log.148Me5e0fbde1e9b3ef24bef5228e2381936568f97d7da5b7214f3883f40bc32c809-json.log.248Me5e0fbde1e9b3ef24bef5228e2381936568f97d7da5b7214f3883f40bc32c809-json.log.348Me5e0fbde1e9b3ef24bef5228e2381936568f97d7da5b7214f3883f40bc32c809-json.log.4重启docker:
dockersystemprune会清理
dockerimageprune-a命令可批量清理悬空镜像
dockerimages看到的none镜像是悬空镜像(danglingimages),即无标签、且不被容器使用的镜像。
搜索DockerHub上的镜像
创建网络时,引擎默认为网络创建一个不重叠的子网。该子网不是现有网络的细分。它纯粹用于IP寻址目的。可以覆盖此默认值,并使用–subnet选项直接指定子网络值。在桥接网络上,只能创建单个子网。创建网络br0dockernetworkcreate--driver=bridge--subnet=192.168.0.0/16br0
dockerrun[OPTIONS]IMAGE[COMMAND][ARG...]以镜像IMAGE启动一个容器,如果IMAGE不存在,会从默认仓库DockerHub上下载此镜像,如果不指定tag默认是latest,启动容器后执行命令COMMAND
例1dockerrun-it--rmubuntu:18.04bash直接运行ubuntu镜像并进入启动的Ubuntu容器ubuntu:18.04:这是指用ubuntu:18.04镜像为基础来启动容器。bash:放在镜像名后的是命令,这里我们希望有个交互式Shell,因此用的是bash
例2dockerrun-itadoptopenjdk/openjdk8:centosbash会直接自动下载centos+jdk镜像,run镜像,并进入容器内
参数-d,--detach让Docker在后台运行而不是直接把执行命令的结果输出在当前宿主机下-e,--envlist启动容器时增加环境变量-p,--publish<宿主端口>:<容器端口>映射宿主端口和容器端口,-p标记可以多次使用来绑定多个端口。例如-p80:8080映射本机80端口到容器内的8080端口-P,--publish-all随机映射宿主机上一个49000~49900之间的端口到容器内部的网络端口--namestring指定启动的容器的名字--restartstring容器退出后的重启策略,默认是no,--restart=always可保持容器一直运行--rm容器退出后随之将其删除。默认情况下,为了启动失败时查错,退出的容器并不会立即删除,除非手动dockerrm。
-i,--interactive则让容器的标准输入保持打开,交互式操作-t,--tty让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上-it这两个参数一起使用,可进入容器执行命令。
--networknetwork,--netnetwork指定容器的网络模式,默认为bridgebridge即桥接网络,以桥接模式连接到宿主机,即宿主机和容器之间通过docker0虚拟网卡连到同一个局域网,bridge是默认的网络模式host宿主网络,即与宿主机共用网络,这种模式相当于没有网络隔离,好处是和宿主机处于同一网络,可随意访问,都不用-p做端口映射了。none则表示无网络,容器将无法联网container:c_name连接到容器c_name的网络network_name连接到预先创建好的网络network_name
-v,--volume[HOST-DIR:]CONTAINER-DIR[:OPTIONS]在本地(宿主机)和容器间映射目录或文件。注意此选项中HOST-DIR可以省略,但CONTAINER-DIR不能省略。如果只有一个目录,会被当做是CONTAINER-DIRHOST-DIR省略时,会自动在本机创建和容器中同名的目录。映射文件时文件名可以不相同。如果HOST-DIR和CONTAINER-DIR都存在,host上的文件/文件夹内容会覆盖container中的文件/文件夹内容。当映射文件时,宿主机文件必须存在,因为如果不存在会自动在宿主机创建,但此时创建的就是目录了。CONTAINER-DIR必须是绝对路径。HOST-DIR可以是绝对路径,或者volume卷名。HOST-DIR是绝对路径是,挂载此路径到容器。HOST-DIR是卷名时,挂载此卷(没有会自动创建volume)到容器。
挂载目录-vA:B时
-v可以出现多次,挂载多个不同的目录。
容器销毁后,启动容器时创建的宿主机目录不会销毁,容器运行过程中对目录的操作也都会保留在宿主机。
--mount挂载本地卷、目录、文件到容器中。由多个键值对组成,由逗号分隔,每一个由key=value元祖组成。键值对没有顺序。type,可以是bind,volume,tmpfs。source,主机上的文件或目录的路径。可能用src,source指定。destination,容器中的文件或目录的路径。可能用destination,dst,target指定。使用-v和–volume绑定主机不存在的文件或目录,将会自动创建。始终创建的是一个目录。使用–mount绑定主机上不存在的文件或目录,则不会自动创建,会产生一个错误。
-u,--user指定容器用户,格式
例如dockerrun-u1000:1000-itubuntubashdockerrun-ucentos-itcentos:7bash
大约在0.6版,privileged被引入docker。使用该参数,container内的root拥有真正的root权限。否则,container内的root只是外部的一个普通用户权限。
M1Mac上运行amd64/x86_64架构镜像,可以指定--platformlinux/amd64参数
dockerrun-d--rm\--platformlinux/amd64\-p8001:8001\--nameblog\-v/var/log/spring:/var/log/spring\-e"SPRING_PROFILES_ACTIVE=local"\blog如果镜像本身是amd64/x86_64架构的,不需要指定,但dockerrun会报警告:WARNING:Therequestedimage’splatform(linux/amd64)doesnotmatchthedetectedhostplatform(linux/arm64/v8)andnospecificplatformwasrequested
1、dockerps-a能显示启动失败的容器,然后dockerlogs-f看启动日志有无报错2、dockerinspect看容器信息
3、如果dockerps-a也看不到容器,可以去掉-d后台运行参数,前台运行,而是-it把容器日志打印到前台,看有什么报错。
其中Architecture是镜像的架构
当用户获取一个镜像时,Docker引擎会首先查找该镜像是否有manifest列表,如果有的话Docker引擎会按照Docker运行环境(系统及架构)查找出对应镜像(例如golang:alpine)。如果没有的话会直接获取镜像(例如上例中我们构建的username/test)。
dockerpull[选项][DockerRegistry地址[:端口号]/]仓库名[:标签]具体的选项可以通过dockerpull–help命令看到Docker镜像仓库地址:地址的格式一般是<域名/IP>[:端口号]。默认地址是DockerHub。仓库名:如之前所说,这里的仓库名是两段式名称,即<用户名>/<软件名>。对于DockerHub,如果不给出用户名,则默认为library,也就是官方镜像。
例如dockerpullubuntu:18.04上面的命令中没有给出Docker镜像仓库地址,因此将会从DockerHub获取镜像。而镜像名称是ubuntu:18.04,因此将会获取官方镜像library/ubuntu仓库中标签为18.04的镜像。
有的镜像同一tag提供多架构的,可通过–platform参数指定架构
dockerpulladoptopenjdk/openjdk8:centos–platformamd64dockerpullcentos:7–platformlinux/amd64
一般默认情况下docker镜像的存放位置为/var/lib/docker(可通过dockerinfo命令查看DockerRootDir配置项),而此目录一般不会分配很大空间,docker上跑的东西太多就会发现此目录满了。
注意:Mac虽然dockerinfo看到的DockerRootDir也是/var/lib/docker,但其实镜像并不在这里,而是在$HOME/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw这个单独的文件中,并且无法修改。
解决方法:
OPTIONS=--graph="/root/data/docker"--selinux-enabled-Hfd://2、如果docker是1.12或以上的版本,可以修改(或新建)/etc/docker/daemon.json文件。修改后会立即生效,不需重启docker服务。改为
ExecStart=/usr/bin/dockerd-g/data/docker/-Hfd://然后systemctldaemon-reload重载unit配置文件
docker镜像所在磁盘空间不足时pullimage会报这个错误。
dockerimagels列出镜像,等价于dockerimages
dockerimagelsubuntu根据仓库名列出镜像dockerimagelsubuntu:18.04指定仓库名和标签列出镜像dockerimagels-q只列出镜像ID,经常用做其他命令的输入参数
dockerimagerm[选项]<镜像1>[<镜像2>...]等价于dockerrmi
dockerimagermcentos用镜像名,也就是仓库名:标签,来删除镜像dockerimagerm$(dockerimagels-qredis)删除所有仓库名为redis的镜像dockerimagerm$(dockerimagels-q-fbefore=mongo:3.2)删除所有在mongo:3.2之前的镜像
dockerbuild[选项]<上下文路径/URL/->-t,--tag指定image文件的名字,后面还可以用冒号指定标签,例如name:tag。如果不指定,默认的标签就是latest-f,--file指定Dockerfile文件名称,默认是PATH/Dockerfile
dockerbuild-tmyapp.在当前目录使用Dockerfile构建myapp镜像dockerbuild-tmyapp-fpath-to-Dockerfile.在当前目录使用path-to-Dockerfile构建myapp镜像
构建amd64架构的镜像
如果Dockerfile中指定了特定架构的基础镜像,例如FROMubuntu:amd64,则构建的镜像继承了基础镜像的架构,因此也是amd64架构的
docker构建命令dockerbuild[选项]<上下文路径/URL/->最后需要制定上下文目录当构建的时候,用户会指定构建镜像上下文的路径,dockerbuild命令得知这个路径后,会将路径下的所有内容打包,然后上传给Docker引擎。这样Docker引擎收到这个上下文包后,展开就会获得构建镜像所需的一切文件。
如果在Dockerfile中这么写:COPY./package.json/app/这并不是要复制执行dockerbuild命令所在的目录下的package.json,也不是复制Dockerfile所在目录下的package.json,而是复制上下文(context)目录下的package.json。
一般来说,应该会将Dockerfile置于一个空目录下,或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。如果目录下有些东西确实不希望构建时传给Docker引擎,那么可以用.gitignore一样的语法写一个.dockerignore,该文件是用于剔除不需要作为上下文传递给Docker引擎的。
实际上Dockerfile的文件名并不要求必须为Dockerfile,而且并不要求必须位于上下文目录中,比如可以用-f../Dockerfile.php参数指定某个文件作为Dockerfile。
.dockerignore用于剔除不需要作为上下文传递给Docker引擎的文件
--no-trunc不截断输出结果,不加这个选项的话CREATEDBY中显示不全
dockercontainerstop等于dockerstopdockerstop[OPTIONS]CONTAINER[CONTAINER...]
dockerrm等于dockercontainerrmdockerrm[OPTIONS]CONTAINER[CONTAINER...]如果要删除一个运行中的容器,可以添加-f参数。Docker会发送SIGKILL信号给容器。
dockerexec等于dockercontainerexecdockerexec[OPTIONS]CONTAINERCOMMAND[ARG...]-it这两个参数一起使用,可进入容器执行命令。常用格式dockerexec-it容器IDbashdockerexec-it容器IDsh
先查看当前运行的容器
原因:原因是该容器并没有bash解决:改用shdockerexec-it33e828194205sh
当我们运行一个容器的时候(如果不使用卷的话),我们做的任何文件修改都会被记录于容器存储层里。而Docker提供了一个dockercommit命令,可以将容器的存储层保存下来成为镜像。换句话说,就是在原有镜像的基础上,再叠加上容器的存储层,并构成新的镜像。以后我们运行这个新镜像的时候,就会拥有原有容器最后的文件变化。
dockercommit[选项]<容器ID或容器名>[<仓库名>[:<标签>]]
-a,--authorstring指定修改的作者-m,--messagestring记录本次修改的内容
$dockercommit\-a"TaoWang
保存镜像到tar文件,默认输出到stdout,默认包含所有的layer,所有的tags,当然也可以指定tags-o,--outputdockersave默认是输出到stdout,通过-o参数可指定保存的档案文件名
dockersavebusybox>busybox.tar保存镜像busybox的所有版本到busybox.tar文件dockersave-omyimage.tarmyimage:tag1保存镜像myimage的tag1版本到myimage.tar文件
方法一、利用gzip/gunzip压缩解压导出镜像并压缩为gzipdockersavemyimage:latest|gzip>myimage_latest.tar.gz导出镜像并压缩
倒入镜像压缩包gunzip-cmyimage_tag.tar.gz|dockerload
方法二、或者使用tar命令压缩和解压
dockersavemyimage:tag>myap.tartar-zcvfmyap.tar.gzmyap.tar解压导入镜像
tar-xzvfmyap.tar.gzdockerload 1、在可以联网的机子上执行dockerpull命令下载镜像,如:sudodockerpullfreewil/bitcoin-testnet-box,命令使用参考Dockerpull命令2、然后运行dockersave命令将镜像保存为tar归档文件,如:dockersave-obitcoin-testnet-box.tarfreewil/bitcoin-testnet-box,命令使用参考Dockersave命令3、将保存的bitcoin-testnet-box.tar归档文件拷贝进内网机器4、内网机器上执行dockload命令加载保存的tar归档文件,如:dockerload-ibitcoin-testnet-box.tar 从tar文件或标准输入stdin导入镜像,会重建镜像和所有的tag.这里的tar文件是用dockersave命令导出的镜像。--input,-i:指定导入的文件,代替STDIN--quiet,-q:精简输出信息。 dockerload dockercp等于dockercontainercpdockercp[OPTIONS]CONTAINER:SRC_PATHDEST_PATH|-dockercp[OPTIONS]SRC_PATH|-CONTAINER:DEST_PATH 示例1、将容器中的文件/root/123.mp4拷贝到宿主机的/root/mp4/目录中,其中335d957237c9是容器id dockercp335d957237c9:/root/123.mp4/root/mp4/2、将容器中的/root/images目录拷贝到宿主机的/root/data/目录中,其中335d957237c9是容器id dockercp335d957237c9:/root/images/root/data/3、将宿主机当前目录中的xx.mp4文件拷贝到容器的/root/data/目录中,其中video-processor是容器名 dockerlogs[OPTIONS]CONTAINER如果容器无法启动,先dockerps-a找到启动失败的容器id,然后dockerlogs容器id查看失败日志注意为了保留启动失败的容器,不能加--rm否则失败后容器文件就被删除了。dockerlogs-f容器id以滚动方式查看容器日志 dockerinspect[OPTIONS]NAME|ID[NAME|ID...] 从Docker20.10.0版本开始,将docker-compose集成到了docker命令中,docker命令内开始包含了compose子命令但这仍然是一个实验性的功能,并不是所有的Docker安装都包含此功能,需要修改~/.docker/config.json"experimental":"enabled"来启用实验性功能,然后重启docker 从Docker20.10.0版本开始,将docker-compose集成到了docker命令中,docker命令内开始包含了compose子命令compose用于定义和运行由多个docker镜像组成的service,可通过配置文件配置service由哪些镜像组成,然后通过一个命令一次性将这些docker镜像启动。 1、下载二进制可执行文件,命名为docker-compose 3、查看版本,有输出就是安装成功 compose文件包含了4个顶级键:version:指定文件规范版本services:指定要操作的容器networks:指定共用的网络配置volumes:指定共用的存储配置 可以使用docker-composeconfig验证和查看待操作的Compose文件 compose配置文件格式版本Docker版本3.819.03.0+3.718.06.0+3.618.02.0+3.517.12.0+3.417.09.0+3.317.06.0+3.217.04.0+3.11.13.1+3.01.13.0+2.417.12.0+2.317.06.0+2.21.13.0+2.11.12.0+2.01.10.0+1.01.9.1.+ 解决容器的依赖、启动先后的问题。以下例子中会先启动redisdb再启动web 如果你使用默认配置文件名称,不需要显式指定-fdocker-compose.yml如若需指定配置文件,必须在docker-compose后面指定,不能在up等子命令后面指定,否则无效; -d,--detach后台启动默认情况,docker-composeup启动的容器都在前台,控制台将会同时打印所有容器的输出信息,可以很方便进行调试。当通过Ctrl-C停止命令时,所有容器将会停止。如果使用docker-composeup-d,将会在后台启动并运行所有的容器。 --no-recreate默认情况,如果服务容器已经存在,docker-composeup将会尝试停止容器,然后重新创建(保持使用volumes-from挂载的卷),以保证新启动的服务匹配docker-compose.yml文件的最新内容。如果用户不希望容器被停止并重新创建,可以使用docker-composeup--no-recreate这样将只会启动处于停止状态的容器,而忽略已经运行的服务。如果需要的话,这样将会启动已经停止的容器。 指定service如果用户只想重新部署某个服务,可以使用docker-composeup--no-deps-d 链接的服务都将会启动,除非他们已经运行。 start启动一个已经存在的服务容器。 停止一个已经运行的容器,但不删除它。通过docker-composestart可以再次启动这些容器。 查看容器,在docker-compose.yml所在目录中执行docker-composeps只查看此compose.yml描述的容器状态 #docker-composepsNameCommandStatePorts-------------------------------------------------------------------------------------------------zookeeper_1/docker-entrypoint.shzkSe...Up0.0.0.0:2181->2181/tcp,2888/tcp,3888/tcpzookeeper_2/docker-entrypoint.shzkSe...Up0.0.0.0:2182->2181/tcp,2888/tcp,3888/tcpzookeeper_3/docker-entrypoint.shzkSe...Up0.0.0.0:2183->2181/tcp,2888/tcp,3888/tcp当然也可以直接dockerps查看所有容器的状态 默认情况下,应用程序的网络名称基于Compose的工程名称,而项目名称基于docker-compose.yml所在目录的名称。如需修改工程名称,可使用–project-name标识或COMPOSE_PORJECT_NAME环境变量。 举个例子,假如一个应用程序在名为myapp的目录中,并且docker-compose.yml如下所示: version:"3"services:web:build:.ports:-"8000:8000"db:image:postgresports:-"8001:5432"当我们运行docker-composeup时,将会执行以下几步: 创建一个名为myapp_default的网络;使用web服务的配置创建容器,它以“web”这个名称加入网络myapp_default;使用db服务的配置创建容器,它以“db”这个名称加入网络myapp_default。 等于docker命令的--network参数 1、注册DockerHub账号 #查看本地镜像$dockerimagesREPOSITORYTAGIMAGEIDCREATEDSIZEmasikkk/centos7-openjdk21202401235996f993958f7weeksago720MBmasikkk/centos7-openjdk21-tesseract2024012315a6611140d740hoursago1.07GB打镜像tag时需要注意名称中必须包含DockerHub账号,我的账号是masikkk,则镜像必须是masikkk/开头,否则推送到DockerHub时报错: library/registry是官方提供的工具,可以用于构建私有的镜像仓库。也就是这个私人仓库程序本身就是一个镜像。使用官方的registry镜像来启动私有仓库。默认情况下,仓库会被创建在容器的/var/lib/registry目录下。通过-v将本地目录/home/centos/docker/registry映射到容器的/var/lib/registry目录,这样上传到容器的镜像就保存到本地了。 crane是一个与远程镜像和仓库交互的工具,由Googlecontainerregistry开发 将本地镜像内容推送到远程仓库crane–insecurepushmyapp-1.2.1.tarlocalhost:5000/myapp:1.2.1 BusyBox是一个集成了一百多个最常用Linux命令和工具(如cat、echo、grep、mount、telnet等)的精简工具箱,它只需要几MB的大小,很方便进行各种快速验证。 dockerbuild-fcentos7-openjdk21-nodejs16-hexo7.Dockerfile-tmasikkk/centos7-openjdk21-node16-hexo7:20240317. dockerrun-d-it--rm\-v~/.ssh:/home/centos/.ssh\masikkk/centos7-openjdk21-node16-hexo7:20240317bash后台启动容器,然后dockerexec进入容器 安装gitsudoyuminstall-ygit 安装nodejs17 只有amd64架构的 AdoptOpenJDK已被官方废弃,最高只到jdk16注意此镜像有多种架构,M1Mac上默认会拉取arm64架构的版本,如果想要使用amd64/x86_64架构版本,需要通过--platformamd64参数指定 dockerpulladoptopenjdk/openjdk8:centos–platformamd64dockerpulladoptopenjdk/openjdk8:centos-slim–platformamd64 REPOSITORYTAGIMAGEIDCREATEDSIZEadoptopenjdk/openjdk8centos-slimf7719a74b21017hoursago471MBadoptopenjdk/openjdk8centosa72f04e4db6d17hoursago579MB 1、创建centos7-openjdk8.Dockerfile FROMcentos:7MAINTAINERmasikkk.comRUNyumupdate-y&&\yuminstall-ywget&&\yuminstall-yjava-1.8.0-openjdkjava-1.8.0-openjdk-devel&&\yumcleanall#Setenvironmentvariables.ENVHOME/root#Defineworkingdirectory.WORKDIR/root#Definedefaultcommand.CMD["java","-version"]2、构建镜像进入centos7-openjdk8.Dockerfile文件所在目录dockerbuild-fcentos7-openjdk8.Dockerfile-tmasikkk/centos7-openjdk8:20240123.结果 $dockerimagesREPOSITORYTAGIMAGEIDCREATEDSIZEmasikkk/centos7-openjdk820240123a44b575730c856secondsago602MB3、运行镜像,由于Dockerfile里的CMD命令就是java-version,执行dockerrun可直接看到java版本 $dockerrunmasikkk/centos7-openjdk8:20240123openjdkversion"1.8.0_392"OpenJDKRuntimeEnvironment(build1.8.0_392-b08)OpenJDK64-BitServerVM(build25.392-b08,mixedmode)也可以执行dockerrun-it--rmcentos7-openjdk8:20240123bash进入镜像看看java版本 4、推送到DockerHub 注意:下面docker镜像的构建是在linux上执行的,如果在M1Mac上打镜像但最后在Linux上跑,需要注意M1Mac上默认会拉下来arm64架构的镜像,而Linux上需要amd64架构的镜像。 1、创建centos7-openjdk21.Dockerfile dockerbuild-fcentos7-openjdk21.Dockerfile-tmasikkk/centos7-openjdk21:20240123.结果: $dockerimagesREPOSITORYTAGIMAGEIDCREATEDmasikkk/centos7-openjdk21202401235996f993958f7weeksago720MB3、执行dockerrunmasikkk/centos7-openjdk21:20240123验证,由于Dockerfile里的CMD命令就是java-version,dockerrun可直接看到java版本 $dockerrunmasikkk/centos7-openjdk21:20240123openjdkversion"21.0.1"2023-10-17OpenJDKRuntimeEnvironment(build21.0.1+12-29)OpenJDK64-BitServerVM(build21.0.1+12-29,mixedmode,sharing)也可以dockerrun-it--rmmasikkk/centos7-openjdk21:20240123bash进入容器验证或者dockerrun-d-it--rmmasikkk/centos7-openjdk21:20240123bash后台启动容器,然后dockerexec进入容器。 1、创建centos7-openjdk21-tesseract.Dockerfile dockerbuild-fcentos7-openjdk21-tesseract.Dockerfile-tmasikkk/centos7-openjdk21-tesseract:20240123.结果: $dockerimagesREPOSITORYTAGIMAGEIDCREATEDSIZEmasikkk/centos7-openjdk21-tesseract2024012315a6611140d740hoursago1.07GB3、执行dockerrunmasikkk/centos7-openjdk21-tesseract:20240123由于CMD默认命令是tesseract-v,可直接看到tesseract版本号: $dockerrunmasikkk/centos7-openjdk21-tesseract:20240123tesseract4.1.3leptonica-1.76.0libjpeg6b(libjpeg-turbo1.2.90):libpng1.5.13:libtiff4.0.3:zlib1.2.7:libwebp0.3.0FoundAVX2FoundAVXFoundFMAFoundSSE也可以dockerrun-it--rmmasikkk/centos7-openjdk21-tesseract:20240123bash进入容器验证。 1、在项目根目录下添加Dockerfile文件: 2、先用maven把springboot项目打包为可运行的jar包mvnpackage 3、构建SpringBootDocker镜像在Dockerfile所在的项目根目录下构建镜像dockerbuild-tblog-server.注意一定要在Dockerfile所在的目录,最后那个.指定了当前目录是构建上下文。 dockerrun-d--rm\--networkhost\--nameblog-server\-v/var/log/spring:/var/log/spring\-e"SPRING_PROFILES_ACTIVE=local"\blog-server解释下 启动后进入容器dockerexec-itblog-serversh查看系统版本 dockerrun-d--rm\-p8001:8001\--nameblog\-v/var/log/spring:/var/log/spring\-e"SPRING_PROFILES_ACTIVE=local"\blogM1Mac上运行amd64/x86_64架构镜像 如果不带标签的话,默认拉取的是latest版本镜像,也就是1.17.9,mainline,1,1.17,latest,这个版本用的是debian:buster-slimlinux,不是很习惯,好多基本命令没有。所以加上alpine标签拉取1.17.9-alpine,mainline-alpine,1-alpine,1.17-alpine,alpine版本镜像 拉取官方nginxalpine版本镜像的最新版dockerpullnginx:alpine 进容器中查看系统版本查看/etc/os-release文件 #nginx-vnginxversion:nginx/1.17.9配置目录/etc/nginx/nginx.conf日志目录/var/log/nginx/error.log/var/log/nginx/access.log 还使用原始的nginx:alpine官方镜像,只不过在启动命令中加入自己的配置,很方便 aws上的nginx dockerrun-d--rm\--networkhost\--namenginx\-eTZ="Asia/Shanghai"\-v/home/centos/git/hexo/nginx/nginx-centos.conf:/etc/nginx/nginx.conf:ro\-v/home/centos/git/hexo/public:/home/centos/git/hexo/public\-v/home/centos/git/image:/home/centos/git/image\-v/var/log/nginx:/var/log/nginx\nginx:alpine解释: 在nginx-centos.conf文件所在的目录中新建Dockerfile文件 FROMnginx:alpineCOPYnginx-centos.conf/etc/nginx/nginx.confRUNecho"Asia/shanghai">/etc/timezone\&&ln-sf/usr/share/zoneinfo/Asia/Shanghai/etc/localtime解释: 在Dockerfile所在目录内执行dockerbuild-tnginx-masikkk.构建自己的nginx镜像,名为nginx-masikkk,以当前路径为上下文路径一定要注意上下文路径是当前所在文件夹,所以COPY指令才可以直接拷贝当前文件夹中的nginx-centos.conf文件 $dockerbuild-tnginx-masikkk.SendingbuildcontexttoDockerdaemon15.87kBStep1/3:FROMnginxlatest:Pullingfromlibrary/nginxDigest:sha256:50cf965a6e08ec5784009d0fccb380fc479826b6e0e65684d9879170a9df8566Status:Downloadednewerimagefornginx:latest--->231d40e811cdStep2/3:COPYnginx-centos.conf/etc/nginx/nginx.conf--->e45c37eea53fStep3/3:RUNecho"Asia/shanghai">/etc/timezone&&cp/usr/share/zoneinfo/Asia/Shanghai/etc/localtime--->Runninginf8cc0a26834aRemovingintermediatecontainerf8cc0a26834a--->20ad396f30eaSuccessfullybuilt20ad396f30eaSuccessfullytaggednginx-masikkk:latest查看构建好的镜像 $dockerimagelsREPOSITORYTAGIMAGEIDCREATEDSIZEnginx-masikkklatest20ad396f30ea4secondsago126MBnginxlatest231d40e811cd4weeksago126MB启动自己的nginx容器 dockerrun-d--rm\--networkhost\--namenginx\-v/home/centos/git/hexo/public:/home/centos/git/hexo/public\-v/home/centos/git/hexo/image:/home/centos/git/hexo/image\-v/var/log/nginx:/var/log/nginx\nginx-masikkk这样启动命令可以少两个参数。 docker版nginx默认以用户nginx启动,一开始我使用了自己当前的用户,一直无法启动报错2019/12/2303:49:40[emerg]1#1:getpwnam(“centos”)failedin/etc/nginx/nginx.conf:2nginx:[emerg]getpwnam(“centos”)failedin/etc/nginx/nginx.conf:2在nginx.conf中改为usernginxnginx;后好了 docker太方便了,准备好配置文件后直接启动就行,自动从dockerhub拉取最新官方镜像我的启动命令如下: dockerrun-d--rm\--networkhost\--nameprometheus\-v/home/centos/git/masikkk/prometheus.yml:/etc/prometheus/prometheus.yml\prom/prometheus解释下:-d后台运行--rm停止容器后删掉容器文件--networkhost与宿主机完全共享网络,默认是bridge桥接,无法在nginx中通过localhost转发请求--namegrafana指定启动的容器名,方便按名称stop等操作-v映射配置文件,具体说是宿主机配置文件覆盖容器中的配置文件,我的配置文件在git仓库中,方便保存,也可以记录修改历史。 第一次执行时直接从dockerhub拉取最新版本grafana dockerrun-d--rm\--networkhost\--namegrafana\grafana/grafana解释下:-d后台运行--rm停止容器后删掉容器文件--networkhost与宿主机完全共享网络,默认是bridge桥接,无法在nginx中通过localhost转发请求--namegrafana指定启动的容器名,方便按名称stop等操作 方法一,bridge网络模式的容器使用宿主机在docker0网卡上的ip访问宿主机。安装Docker的时候,会在宿主机安装一个虚拟网卡docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。在宿主机上ifconfig查看docker0网卡的ip地址,Linux下一般是172.17.0.1,macOS下一般是192.168.65.1,并不固定。在容器中使用宿主机ip访问的问题是,配置写死ip非常不灵活,和dockeranywheredeploy的原则相悖。 方法二,使用host宿主机网络模式启动容器Docker容器运行的时候有host、bridge、none三种网络可供配置。默认是bridge,即桥接网络,以桥接模式连接到宿主机;host是宿主网络,即与宿主机共用网络;none则表示无网络,容器将无法联网。 当容器使用host网络时,容器与宿主共用网络,这样就能在容器中访问宿主机网络,那么容器的localhost就是宿主机的localhost。启动容器时加参数--networkhost表示已宿主机网络模式启动容器。此时不需要-p80:80做端口映射了,因为本身与宿主机共用了网络,容器中暴露端口等同于宿主机暴露端口。这种模式的问题是破坏了容器之间的隔离性,好处是网络访问很方便。 容器中的nginx日志文件都重定向到了重启的标准输出和标准错误输出,所以直接到容器中看access.log是没有内容的。有如下两个方法看日志:1、可以在容器外通过dockerlogs-fnginx-name查看日志/var/log/nginx/access.log->/dev/stdout/var/log/nginx/error.log->/dev/stderr 2、启动容器时-v/var/log/nginx:/var/log/nginx将容器内日志目录映射到本机,之后直接在本机即可看日志。 在alpine镜像中使用诸如jstack,jinfo工具,有如下报错:1:UnabletogetpidofLinuxThreadsmanagerthread 原因是pid为1,发现PID为1的时候,工具不可用。 解决:1、Dockerfile里使用如下命令启动:CMD["/bin/sh","-c","javaAPP","&&1"]2、或者使用--init参数来启动docker docker启动springbootjava服务报错: [0.007s][warning][os,thread]Failedtostartthread"GCThread#0"-pthread_createfailed(EPERM)forattributes:stacksize:1024k,guardsize:4k,detached.##ThereisinsufficientmemoryfortheJavaRuntimeEnvironmenttocontinue.#CannotcreateworkerGCthread.Outofsystemresources.#Anerrorreportfilewithmoreinformationissavedas:#//hs_err_pid7.log解决:docker启动命令添加参数--privileged特权模式 某些需要绘制图表的java应用在docker中可能遇到这个问题,比如需要创建excel表格的,原因是缺少字体配置。 可以进入容器修改时区,不推荐dockerexec-it 启动容器时用环境变量TZ指定时区dockerrun-eTZ="Asia/Shanghai"-d-p80:80--namenginxnginx 启动容器时-v绑定主机时区文件利用volume可以在启动一个container时指定使用主机的时区文件,就可以把container的时区与主机同步dockerrun-v/etc/localtime:/etc/localtime 如果是打包自己的镜像,可以在Dockerfile中增加 RUNecho"Asia/shanghai">/etc/timezone\&&ln-sf/usr/share/zoneinfo/Asia/Shanghai/etc/localtime前提是容器的linux中本身就有/usr/share/zoneinfo/Asia/Shanghai时区文件 alpine中默认也是UTC时区,需要改为东八区,但alpine中默认又没有/usr/share/zoneinfo/Asia/Shanghai时区文件,只能先安装时区文件tzdata,再链接到/etc/localtime 因为通过-v映射了一个不在共享配置中的文件夹 Mac系统中想要和容器共享文件夹的话,需要先配置默认已共享了/Users/,/Volumes/,/private/,and/tmp可在Preferences->Filesharing中增加共享目录 mac中没有docker0虚拟网卡受限于DockerDesktopforMac底层的网络实现,Mac上的docker没有docker0网卡。 从容器中访问mac网络的方法通过调试用DNShost.docker.internal 从mac上访问容器网络的方法:使用-p80:80暴露端口,--networkhost不起作用 为了在M1Mac上模拟运行amd64/x86_64架构的Linux环境,需要构建和运行amd64/x86_64架构镜像。 1、M1Mac上构建amd64/x86_64架构镜像dockerbuild-fdevops/blog.Dockerfile–platform=amd64-tblog. 2、M1Mac上运行amd64/x86_64架构镜像,可以指定--platformlinux/amd64参数