【Docker】基础篇

文章目录

Docker为什么出现

一款产品从开发到上线,至少与两套环境,包括应用环境,应用配置,而环境配置是十分的麻烦,每一个机器都要部署一样的环境,费事费力

问题:发布一个项目,该项目能不能带上环境安装打包一起发布

Docker给以上的问题,提出了解决方案(Docker的思想就来自于集装箱

隔离:Docker核心思想就是隔离,将每个版本打包装箱,每个箱子是互相隔离的

  • Docker通过隔离机制,可以将服务器利用到极致

容器和虚拟机

关于虚拟机

在容器技术出来之前,都是使用虚拟机技术,但是虚拟机和docker容器都是一种虚拟化技术

  • 虚拟机:在window中装一个VMware,通过这个软件我们可以虚拟出来一台或者多台电脑,比较笨重

虚拟机技术:

虚拟机技术缺点:资源占用多 冗余步骤多 启动很慢

关于Docker

Docker基于Go语言开发的,是开源项目

容器化技术

容器化技术不是模拟一个完整的操作系统

二者区别:

1.虚拟化级别不同

  • 虚拟机是基于硬件层面的虚拟化技术,它通过在物理服务器上创建虚拟硬件层来模拟完整的操作系统和硬件环境,传统虚拟机:虚拟出一套硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件
  • 容器是在操作系统层面进行虚拟化,利用操作系统的隔离机制来创建独立的运行环境,容器内的应用直接运行在宿主机的内核当中容器是没有自己的内核的,也没有虚拟我们的硬件,所以就轻便了

2.资源利用效率

  • 由于虚拟机需要模拟完整的操作系统和硬件环境,因此每个虚拟机都需要独立的操作系统和额外的系统资源。这使得虚拟机在资源利用方面相对较低
  • 容器共享宿主机的操作系统,容器之间共享内核,因此容器可以更高效地利用系统资源,每个容器间是互相隔离,每个容器内都有一个属于自己的文件系统,互不影响

3.启动时间

  • 虚拟机启动需要较长的时间,因为它需要启动完整的操作系统
  • 容器启动通常更快,因为它们共享宿主机的操作系统和内核

4.隔离性

  • 虚拟机提供了更强的隔离性,因为每个虚拟机都有自己独立的操作系统和硬件模拟
  • 容器在隔离性方面相对较弱,因为它们共享操作系统和内核,容器之间的隔离依赖于容器技术本身提供的机制

5.迁移和扩展性

  • 虚拟机可以在不同的物理服务器之间迁移,但迁移过程相对较慢和复杂
  • 容器可以更快速地迁移和扩展,因为它们是轻量级的,且依赖于宿主机的操作系统

docker对于DevOps(开发、运维)的用途

1.应用更快速的交付和部署

  • 传统做法:一对帮助文档,安装程序。

  • Docker做法:打包镜像发布测试一键运行。

2.更便捷的升级和扩缩容:使用了 Docker之后,我们部署应用就和搭积木一样,项目打包为一个镜像,然后扩展服务器A,服务器B

3.更简单的系统运维:在容器化之后,我们的开发,测试环境都是高度一致的

4.更高效的计算资源利用Docker是内核级别的虚拟化,可以在物理机上可以运行很多的容器实例!服务器的性能可以被压榨到极致


Docker的基本组成

相关概念-镜像,容器,仓库

**镜像(image):**docker镜像就好比是一个模板,可以通过这个模板来创建容器服务,通过运行tomcat镜像=>得到tomcat容器(提供服务器),通过这个镜像可以创建多个容器(最终服务或者项目就是在容器中运行的)

**容器(container):**Docker利用容器技术,独立运行一个或者一组应用,容器是通过镜像来创建的,可以把容器理解为就是一个简易的 Linux系统

**仓库(repository):**仓库就是存放镜像的地方,仓库分为公有仓库和私有仓库。(很类似git),官方Docker Hub默认是国外的,阿里云等平台都有容器服务(需要配置镜像加速)

安装Docker

环境准备

1.Linux要求内核3.0以上 2.CentOS 7

环境查看

shell 复制代码
[root@Mango ~]# uname -r
3.10.0-514.26.2.el7.x86_64	# 要求3.0以上
[root@Mango ~]# cat /etc/os-release 
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"

CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"

docker帮助文档:https://docs.docker.com/engine/install/

卸载与安装

shell 复制代码
#1.卸载旧版本
yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
#2.需要的安装包
yum install -y yum-utils

#3.设置镜像的仓库
yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
#上述方法默认是从国外的,不推荐

#推荐使用国内的(使用阿里云镜像)
yum-config-manager \
    --add-repo \
    https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    
#更新yum软件包索引
yum makecache fast

#4.安装docker相关的 docker-ce是社区版,而docker-ee是企业版
yum install docker-ce docker-ce-cli containerd.io # 这里我们使用社区版即可

#5.启动docker
systemctl start docker

#6. 使用docker version查看是否按照成功
docker version

#7. 测试
docker run hello-world

#8.查看已经下载的镜像(从这里可以查看已有镜像的id)
[root@Mango ~]# docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
hello-world           latest              bf756fb1ae65        4 months ago      13.3kB

卸载docker

shell 复制代码
#1. 卸载依赖
yum remove docker-ce docker-ce-cli containerd.io

#2. 删除资源
rm -rf /var/lib/docker

# /var/lib/docker 是docker的默认工作路径!

阿里云镜像加速

步骤1:登录阿里云找到容器服务

步骤2:找到镜像加速器

步骤3:配置使用

shell 复制代码
#1.创建一个目录
sudo mkdir -p /etc/docker

#2.编写配置文件
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://t2wwyxhb.mirror.aliyuncs.com"]
}
EOF

#3.重启服务
sudo systemctl daemon-reload
sudo systemctl restart docker

docker run的原理

底层原理

Docker是一个Client-Server结构的系统,Docker的守护进程运行在主机上,通过Socket和客户端进行通信,当Docker-Server接收到Docker-Client的指令,就会执行这个命令

docker run 流程图

例子:docker run hello

1)检查本地是否存在 hello 镜像: Docker 首先会检查本地主机上是否存在名为 "hello" 的镜像,如果本地不存在该镜像,Docker 将会去远程仓库下载该镜像。

2)创建容器: 一旦 Docker 获得了 hello 镜像,它会在本地主机上创建一个容器。这个容器是hello镜像的一个实例,包含了运行 hello 应用程序所需的文件系统、代码和依赖项 (该容器是一个隔离的运行环境,与主机和其他容器隔离开来)

3)启动容器: 一旦容器创建成功,Docker 会启动它**,启动容器的过程包括分配资源(如 CPU、内存等)以及配置网络和存储等相关设置**

4)运行 hello 应用程序: 一旦容器启动,Docker 将在容器内部执行 hello 应用程序,这可能涉及到在容器中启动一个进程、执行相关指令或者运行脚本


为什么容器比虚拟机快

一个很重要的原因就是:docker有着比虚拟机更少的抽象层

  • 由于docker不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源,因此在CPU、内存利用率上docker将会在效率上有明显优势
  • docker利用的是宿主机的内核,而不需要像虚拟机一样,需要虚拟化一个操作系统:Guest OS
    • GuestOS: VM(虚拟机)里的的系统(OS) HostOS:物理机里的系统(OS)

当新建一个虚拟机时,虚拟机软件需要虚拟化一个操作系统,:GuestOS,返个虚拟化新建过程是分钟级别 的,而docker由于直接利用宿主机的操作系统,则省略了这个复杂的过程,因此新建一个docker容器只需要几秒钟(docker不需要和虚拟机一样重新加载一个操作系统内核)

Docker的常用命令

1.帮助命令

docker帮助文档的地址:https://docs.docker.com/engine/reference/commandline/build/

shell 复制代码
docker version    #显示docker的版本信息。
docker info       #显示docker的系统信息,包括镜像和容器的数量
docker 命令 --help #帮助命令

2.镜像相关命令

shell 复制代码
docker images #查看所有本地主机上的镜像 可以使用docker image ls代替
docker search 镜像名 #搜索镜像
docker pull 镜像名 #下载镜像 =>完整指令:docker image pull 镜像名
docker rmi 镜像名 #删除镜像 =>完整指令:  docker image rm 镜像名    (i代表image)

docker images查看所有本地的主机上的镜像

shell 复制代码
[root@Mango ~]# docker images
REPOSITORY            TAG                 IMAGE ID            CREATED           SIZE
hello-world           latest              bf756fb1ae65        4 months ago     13.3kB
mysql                 5.7                 b84d68d0a7db        6 days ago       448MB

# 解释 
#REPOSITORY			# 镜像的仓库源
#TAG				# 镜像的标签(版本)		---lastest 表示最新版本
#IMAGE ID			# 镜像的id
#CREATED			# 镜像的创建时间
#SIZE				# 镜像的大小

# 可选项
Options:
  -a, --all         Show all images (default hides intermediate images) #列出所有镜像
  -q, --quiet       Only show numeric IDs # 只显示镜像的id
  
[root@Mango ~]# docker images -a  #列出所有镜像详细信息
[root@Mango ~]# docker images -aq #列出所有镜像的id

docker search: 搜索镜像

shell 复制代码
[root@Mango ~]# docker search mysql

#如果加上 --filter=STARS=3000 #进行过程,表示搜索出来的镜像收藏STARS数量大于3000的
#docker search --help查看相关内容
Options:
  -f, --filter filter   Fi	lter output based on conditions provided
      --format string   Pretty-print search using a Go template
      --limit int       Max number of search results (default 25)
      --no-trunc        Don't truncate output
      
[root@Mango ~]# docker search mysql --filter=STARS=3000
NAME        DESCRIPTION         STARS            OFFICIAL        AUTOMATED
mysql       MySQL IS ...        9520             [OK]                
mariadb     MariaDB IS ...      3456             [OK]   

docker pull 下载镜像

shell 复制代码
# 下载镜像 docker pull 镜像名[:tag]  
#可以版本(tag)的原因可以指定下载某个版本,否则都是下载最新版latest
[root@Mango ~]# docker pull tomcat:8
8: Pulling from library/tomcat #如果不写tag(docker pull tomcat)  默认就是latest   
90fe46dd8199: Already exists   #分层下载: docker的核心 => 联合文件系统
35a4f1977689: Already exists 
bbc37f14aded: Already exists 
74e27dc593d4: Already exists 
93a01fbfad7f: Already exists 
1478df405869: Pull complete 
64f0dd11682b: Pull complete 
68ff4e050d11: Pull complete 
f576086003cf: Pull complete 
3b72593ce10e: Pull complete 
Digest: sha256:0c6234e7ec9d10ab32c06423ab829b32e3183ba5bf2620ee66de866df # 签名防伪
Status: Downloaded newer image for tomcat:8
docker.io/library/tomcat:8 #真实地址

#等价于
docker pull tomcat:8 => docker pull docker.io/library/tomcat:8

注意:版本不能瞎写,必须是存在的

docker rmi 删除镜像

shell 复制代码
docker rmi -f 镜像id #删除指定id的镜像
[root@Mango ~]# docker rmi -f f19c56ce92a8

docker rmi -f $(docker images -aq) #删除全部的镜像   docker images -aq #列出所有镜像的id

3.容器命令

dockerfile 复制代码
docker ps #列出所有运行的容器  等价于docker container list
docker rm 容器id #删除指定容器
docker start 容器id	#启动指定容器
docker restart 容器id	#重启指定容器
docker stop 容器id	#停止当前正在运行的容器
docker kill 容器id	#强制停止当前容器

说明:有了镜像才可以创建容器,下述我们可以通过下载centos镜像来学习

镜像下载

dockerfile 复制代码
#docker中下载centos
docker pull centos
docker run 镜像id #根据镜像新建容器并启动
新建容器并启动
shell 复制代码
docker run [可选参数] image | docker container run [可选参数] image 
#参书说明
--name="Name"		#容器名字Name tomcat01 tomcat02 用来区分容器
-d					#后台方式运行 
-it 				#使用交互方式运行,进入容器查看内容
-p					#指定容器的端口 -p 8080(宿主机):8080(容器)
#有下述4种指定端口的方式
		-p 指定ip:主机端口:容器端口
		-p 主机端口:容器端口          (常用)
		-p 容器端口
		容器端口     (不带-p选项,直接写端口)
-P(大写) 				随机指定端口

# 测试、启动并进入容器
[root@Mango ~]# docker run -it centos /bin/bash
[root@241b5abce65e /]# ls  #注意此时的主机名变成了镜像id   查看容器内的centos
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@Mango /]# exit #从容器退回主机  (或者ctrl+d退出)
exit

/*
docker run -it centos /bin/bash:这个命令在启动 centos 镜像的容器后,会立即执行 /bin/bash 命令,进入容器的交互式终端(bash shell)。这样你可以在容器内执行命令、浏览文件系统、安装软件等操作。

docker run -it centos:这个命令在启动 centos 镜像的容器后,默认会执行容器内的默认命令,通常是启动容器内的主进程。对于 CentOS 镜像来说,它启动之后的默认命令是 /bin/bash,所以在这种情况下,它与上述命令的效果是一样的
但是,如果你使用的是其他镜像,它的默认命令可能是不同的,比如启动一个 Web 服务器进程或者数据库服务
*/
列出所有运行的容器
shell 复制代码
docker ps 命令  		#列出当前正在运行的容器
  -a,      	 #列出当前正在运行的容器 + 历史运行过的容器
  -n=?       #列出最近创建的?个容器 ?为1则只列出最近创建的一个容器,为2则列出2个
  -q,        #只列出容器的编号
退出容器
shell 复制代码
exit 		#容器直接退出  
			#1.容器停止。会导致容器停止运行,容器中的任何正在运行的进程将被中止,并且容器将不再处于运行状态 =>docker ps查看不到该容器的信息
			#2.数据丢失。如果在退出容器之前没有保存或持久化关键数据,那么退出容器将导致在下次启动容器时丢失这些数据。容器中的临时文件和运行时状态将丢失
ctrl +P +Q  #容器不停止退出 =>分离(detach)容器,使容器在后台运行,而无需终止容器进程 	---注意:这个很有用的操作!!!!
删除容器
bash 复制代码
docker rm 容器id   				#删除指定的容器,不能删除正在运行的容器,如果要强制删除,可以加上-rf选项

#删除所有的容器
docker rm -f $(docker ps -aq)  	 #方式1
docker ps -aq|xargs docker rm  #方式2

/*
xargs: 这是一个用于处理命令行参数的工具。它可以将前一个命令的输出作为后一个命令的参数
docker rm: 这是一个用于删除 Docker 容器的命令,它接受一个或多个容器的 ID(或名称)作为参数,并删除这些容器。
因此上述命令的含义是:列出所有容器的 ID,将它们传递给 docker rm 命令以删除这些容器
*/
启动和停止容器
shell 复制代码
docker start 容器id	#启动容器
docker restart 容器id	#重启容器
docker stop 容器id	#停止当前正在运行的容器
docker kill 容器id	#强制停止当前容器

4.常用其他命令

后台启动命令(run -d选项)
shell 复制代码
# 命令 docker run -d 镜像名
[root@Mango ~]# docker run -d centos   #后台运行centos
a8f922c255859622ac45ce3a535b7a0e8253329be4756ed6e32265d2dd2fac6c

[root@Mango ~]# docker ps    
CONTAINER ID      IMAGE       COMMAND    CREATED     STATUS   PORTS    NAMES

问题: docker ps(查看正在运行的容器) 发现centos容器 停止了

常见的坑:docker容器使用后台运行,就必须要有要一个前台进程,docker发现没有前台应用,就会自动停止

  • 容器启动后,docker发现自己没有提供服务,docker就会立刻停止,就是没有程序,使用docker ps查看不到,所以最好的就是: 启动后台应用的情况下,最好要有前台应用与之对应

注意:在docker run命令中使用-d标志创建容器时,容器将在后台以守护进程的形式运行,但是,如果没有指定一个持续运行的进程或命令或者前台进程,容器会在启动后立即退出


解决办法1:在后台运行的容器当中增加一个持续运行的前台进程

  • /bin/sh -c "while true;do echo 6666;sleep 1;done":作为容器的启动命令,这是一个用/bin/sh解释器执行的命令字符串。该命令字符串包含一个无限循环,每秒打印一次字符串"6666"
  • 在这种情况下,使用-d标志是重要的,希望容器在后台持续运行而不阻塞终端。如果不使用-d标志,则命令将在前台运行,将看到输出并且无法继续输入其他命令

解决办法2:docker run -d centos tail -f /dev/null

  • tail -f /dev/null是一个常用的技巧,它提供了一个无限循环的命令,它会持续读取/dev/null(空设备)并保持容器处于运行状态。/dev/null是一个特殊的设备文件,它会将所有写入它的数据丢弃,而读取它将始终返回空值
  • 通过在容器中运行tail -f /dev/null,您实际上在容器中创建了一个持续运行的进程,该进程不会做任何实际的工作,但会阻止容器退出。这样,您就可以保持CentOS容器持续运行而不会立即退出
查看日志
shell 复制代码
docker logs --help
Options:
      --details        Show extra details provided to logs 
*  -f, --follow         Follow log output
      --since string   Show logs since timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)
*      --tail string    Number of lines to show from the end of the logs (default "all")
*  -t, --timestamps     Show timestamps
      --until string   Show logs before a timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)
      
#示例
docker run -d centos /bin/sh -c "while true;do echo 6666;sleep 1;done" #在后台运行的容器当中,模拟日志打印   

#显示日志
-tf		#显示日志信息(一直更新)
--tail number #需要显示日志条数
docker logs -t --tail n 容器id #查看n行日志
docker logs -tf 容器id #实时更新日志

实时查看日志:

指定行数查看日志:


查看容器内部的进程信息
shell 复制代码
docker top 容器id
查看镜像的元数据
shell 复制代码
docker inspect 容器id

#测试 
docker inspect 55321bcae33d  #可以发现这个容器id只是下面的Id的缩写

[
    {
        "Id": "55321bcae33d15da8280bcac1d2bc1141d213bcc8f8e792edfd832ff61ae5066",
        "Created": "2020-05-15T05:22:05.515909071Z",
        "Path": "/bin/sh",
        "Args": [
            "-c",
            "while true;do echo 6666;sleep 1;done"
        ],
        //........
]
进入当前正在运行的容器

我们通常启动容器都是使用后台方式运行 的,但是有时需要进入容器,修改一些配置,docker exec命令可以让我们进入容器

方式1:

docker 复制代码
docker exec -it 容器id bashshell (/bin/shell)

测试

bash 复制代码
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS         PORTS     NAMES
d8010c37caaf   centos    "/bin/bash"   4 seconds ago   Up 3 seconds             tender_greider
[root@localhost ~]# docker exec -it d8010c37caaf /bin/bash
[root@d8010c37caaf /]# pwd
/
[root@d8010c37caaf /]# exit
exit
[root@localhost ~]# 
shell 复制代码
# 方式二
docker attach 容器id

docker attachdocker exec的区别

  • docker exec #进入当前容器后开启一个新的终端(进程),并与容器进行交互,而不会影响容器的原始进程
    • docker exec命令在容器中启动的进程是新的进程,与容器的主进程相互独立
  • docker attach # 进入容器正在执行的终端 不会启动新的进程

所以说:docker attach:连接到容器后,按下 Ctrl+C 将会导致容器停止(除非容器中有其他进程在运行),docker exec:在容器内部启动的进程是新的进程,与容器的主进程相互独立。当您在容器中执行命令并退出后,容器仍然保持运行状态


应用场景

docker attach命令在以下情况下:实时查看容器的输出:如果您需要实时查看容器的输出,例如日志或控制台输出,可以使用docker attach连接到容器的标准流。这允许您直接与容器的主进程进行交互,并查看输出。

docker exec命令适用于以下情况:在容器内执行一次性命令:如果您需要在容器内部执行一次性的命令,例如安装软件包、执行脚本或检查容器的状态,docker exec是更合适的选择。它启动一个新的进程在容器内执行命令,并返回结果


从容器内的内容拷贝到主机上
shell 复制代码
docker cp 容器id:容器内路径  主机目的路径  #注意是在主机执行该命令,而不是在容器内部执行

[root@Mango ~]# docker ps
CONTAINER ID     IMAGE    COMMAND     CREATED         STATUS       PORTS      NAMES
56a5583b25b4     centos   "/bin/bash" 7seconds ago    Up 6 seconds      

#1. 进入docker容器内部
[root@Mango ~]# docker exec -it 56a5583b25b4 /bin/bash
[root@55321bcae33d /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var 

#在容器内新建一个文件
[root@55321bcae33d /]# echo "hello" > hello.java
[root@55321bcae33d /]# cat hello.java 
hello
[root@55321bcae33d /]# exit
exit

#将容器内的hello.java拷贝到主机的home文件夹下
[root@Mango /]# docker cp 56a5583b25b4:/hello.java /home 
[root@Mango /]# cd /home
[root@Mango home]# ls -l	#可以看见hello.java存在
total 8
-rw-r--r-- 1 root root    0 May 19 22:09 haust.java
-rw-r--r-- 1 root root    6 May 22 11:12 hello.java
drwx------ 3 www  www  4096 May  8 12:14 www

命令小结:

shell 复制代码
attach      Attach local standard input, output, and error streams to a running container#将本地标准输入、输出和错误流连接到运行中的容器
build       Build an image from a Dockerfile # 通过Dockerfile定制镜像
commit      Create a new image from a container's changes #提交当前容器为新的镜像
cp          Copy files/folders between a container and the local filesystem #拷贝文件
create      Create a new container #创建一个新的容器
diff        Inspect changes to files or directories on a container's filesystem #查看docker容器的变化
events      Get real time events from the server # 从服务获取容器实时时间
exec        Run a command in a running container # 在运行中的容器上运行命令
export      Export a container's filesystem as a tar archive #导出容器文件系统作为一个tar归档文件[对应import]
history     Show the history of an image # 展示一个镜像形成历史
images      List images #列出系统当前的镜像
import      Import the contents from a tarball to create a filesystem image #从tar包中导入内容创建一个文件系统镜像
info        Display system-wide information # 显示全系统信息
inspect     Return low-level information on Docker objects #查看容器详细信息
kill        Kill one or more running containers # kill指定docker容器
load        Load an image from a tar archive or STDIN #从一个tar包或标准输入中加载一个镜像[对应save]
login       Log in to a Docker registry #登录到 Docker 注册表
logout      Log out from a Docker registry#从 Docker 注册表注销
logs        Fetch the logs of a container#获取容器的日志
pause       Pause all processes within one or more containers#暂停一个或多个容器内的所有进程
port        List port mappings or a specific mapping for the container#列出容器的端口映射或特定映射
ps          List containers#列出容器
pull        Pull an image or a repository from aregistry #从注册表拉取镜像或仓库
push        Push an image or a repository to a registry#将镜像或仓库推送到注册表
rename      Rename a container#重命名一个容器
restart     Restart one or more containers#重新启动一个或多个容器
rm          Remove one or more containers#删除一个或多个容器
rmi         Remove one or more images#删除一个或多个镜像 (image:镜像)
run         Run a command in a new container#在新容器中运行命令
save        Save one or more images to a tar archive (streamed to STDOUT by default)#将一个或多个镜像保存为 tar 归档(默认流式传输到 STDOUT)
search      Search the Docker Hub for images#在 Docker Hub 中搜索镜像
start       Start one or more stopped containers #启动一个或多个已停止的容器
stats       Display a live stream of container(s) resource usage statistics#显示容器的资源使用统计信息的实时流
stop        Stop one or more running containers #停止一个或多个正在运行的容器
tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE#创建一个指向源镜像的目标镜像的标签
top         Display the running processes of a container#显示一个容器内的运行进程
unpause     Unpause all processes within one or more containers#取消暂停一个或多个容器内的所有进程
update      Update configuration of one or more containers #更新一个或多个容器的配置
version     Show the Docker version information#显示 Docker 版本信息
wait        Block until one or more containers stop, then print their exit codes #阻塞直到一个或多个容器停止,然后打印它们的退出代码。

案例一:Docker安装Nginx

shell 复制代码
#1. 搜索镜像 search 建议大家去docker官网搜索,可以看到帮助文档
[root@Mango ~]# docker search nginx

#2. 拉取下载镜像 pull
[root@Mango ~]# docker pull nginx

#3. 查看是否下载成功镜像
[root@Mango ~]# docker images

#3. 运行测试  docker run
#选项: -d 后台运行  --name 给容器命名-p 宿主机端口:容器内部端口   
[root@Mango ~]# docker run -d --name nginx01 -p 3344:80 nginx
aa664b0c8ed98f532453ce1c599be823bcc1f3c9209e5078615af416ccb454c2

#4. 查看正在启动的镜像
[root@Mango ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
75943663c116        nginx               "nginx -g 'daemon of..."   41 seconds ago      Up 40 seconds       0.0.0.0:82->80/tcp   nginx00

#可以使用本机进行测试:curl localhost:3344

#5. 进入容器
[root@Mango ~]# docker exec -it nginx01 /bin/bash 
root@aa664b0c8ed9:/# whereis nginx	#找到nginx配置文件
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@aa664b0c8ed9:/# cd /etc/nginx/
root@aa664b0c8ed9:/etc/nginx# ls
conf.d	fastcgi_params	koi-utf  koi-win  mime.types  modules  nginx.conf  scgi_params	uwsgi_params  win-utf

#6. 退出容器
root@aa664b0c8ed9:/etc/nginx# exit
exit

#7. 停止容器
[root@Mango ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
aa664b0c8ed9        nginx               "nginx -g 'daemon of..."   10 minutes ago      Up 10 minutes       0.0.0.0:3344->80/tcp   nginx01
[root@Mango ~]# docker stop aa664b0c8ed9

宿主机端口容器内部端口 以及端口暴露(映射):(端口映射功能允许将容器内部的端口映射到主机上的端口

  • 通过端口映射,可以轻松将容器内的服务暴露给外部网络,使得可以通过主机的 IP 地址和端口访问容器中的应用程序,这对于开发和部署应用程序非常有用
  • 此时访问主机的3344端口就相当于访问容器的80端口的nginx服务

**问题:**我们每次改动nginx配置文件,都需要进入容器内部?

这是十分麻烦,我要是可以在容器外部提供一个映射路径,达到在容器外部修改文件,容器内部的文件就可以自动修改

  • 此时需要的是数据卷 技术!例如:docker run -v 主机内的目录:容器内的目录通过docker run命令的-v选项进行两个目录之间的挂载

案例二:Docker安装tomcat

坑点:解决webapps目录为空

shell 复制代码
# 例如:下载 tomcat9.0
# 之前的启动都是后台,停止了容器,虽然在docker ps查看不到,但是加上-a选项还是可以查到

# docker run -it --rm 镜像名   如果加上--rm选项,那么一般是用来测试,用完就删除,不会存在历史记录
#           --rm       Automatically remove the container when it exits 用完即删

# docker run 命令会在本地不存在指定镜像时自动下载该镜像
[root@Mango ~]# docker run -it --rm tomcat:9.0  #指定下载9.0版本

#如果不指定版本,默认下载最新版latest
[root@Mango ~]# docker pull tomcat

#查看下载的镜像
[root@Mango ~]# docker images

#以后台方式-d,进行端口映射方式-p,指定启动之后的容器名字为tomcat-1(--name选项) 启动运行tomcat容器  主机的8080端口和容器内的8080端口映射
[root@Mango ~]# docker run -d -p 8080:8080 --name tomcat01 tomcat

#本地测试访问有没有问题
curl localhost:8080

#如果直接去浏览器上访问会出现404,原因是文件缺失,看下面的解决方案

#根据容器id进入tomcat容器
[root@Mango ~]# docker exec -it 645596565d3f /bin/bash
root@645596565d3f:/usr/local/tomcat# 
#查看tomcat容器内部内容:
root@645596565d3f:/usr/local/tomcat# ls -l
total 152
-rw-r--r-- 1 root root 18982 May  5 20:40 BUILDING.txt
-rw-r--r-- 1 root root  5409 May  5 20:40 CONTRIBUTING.md
-rw-r--r-- 1 root root 57092 May  5 20:40 LICENSE
-rw-r--r-- 1 root root  2333 May  5 20:40 NOTICE
-rw-r--r-- 1 root root  3255 May  5 20:40 README.md
-rw-r--r-- 1 root root  6898 May  5 20:40 RELEASE-NOTES
-rw-r--r-- 1 root root 16262 May  5 20:40 RUNNING.txt
drwxr-xr-x 2 root root  4096 May 16 12:05 bin
drwxr-xr-x 1 root root  4096 May 21 11:04 conf
drwxr-xr-x 2 root root  4096 May 16 12:05 lib
drwxrwxrwx 1 root root  4096 May 21 11:04 logs
drwxr-xr-x 2 root root  4096 May 16 12:05 native-jni-lib
drwxrwxrwx 2 root root  4096 May 16 12:05 temp
drwxr-xr-x 2 root root  4096 May 16 12:05 webapps
drwxr-xr-x 7 root root  4096 May  5 20:37 webapps.dist
drwxrwxrwx 2 root root  4096 May  5 20:36 work
root@645596565d3f:/usr/local/tomcat# 
#进入webapps目录
root@645596565d3f:/usr/local/tomcat# cd webapps
root@645596565d3f:/usr/local/tomcat/webapps# ls
root@645596565d3f:/usr/local/tomcat/webapps# 
# 发现问题:1、linux命令少了。 2.webapps目录为空 
# 原因:安装docker的时候使用的是阿里云镜像
#而阿里云默认是最小的镜像,所以不必要的内容都剔除掉,保证最小可运行的环境!
# 解决方案:将webapps.dist下的文件都拷贝到webapps下即可
root@645596565d3f:/usr/local/tomcat#ls   #找到webapps.dist
BUILDING.txt	 LICENSE  README.md	 RUNNING.txt  conf  logs  temp     webapps.dist
CONTRIBUTING.md  NOTICE   RELEASE-NOTES  bin   lib   na	tive-jni-lib  webapps  work

root@645596565d3f:/usr/local/tomcat# cd webapps.dist/ # 进入webapps.dist 
root@645596565d3f:/usr/local/tomcat/webapps.dist# ls # 查看内容
ROOT  docs  examples  host-manager  manager

root@645596565d3f:/usr/local/tomcat/webapps.dist# cd ..
root@645596565d3f:/usr/local/tomcat# cp -r webapps.dist/* webapps # 拷贝webapps.dist 内容给webapps
root@645596565d3f:/usr/local/tomcat# cd webapps #进入webapps
root@645596565d3f:/usr/local/tomcat/webapps# ls #查看拷贝结果
ROOT  docs  examples  host-manager  manager

这样docker部署tomcat就可以访问了


问题:我们以后要部署项目,如果每次都要进入容器是不是十分麻烦?要是可以在容器外部提供一个映射路径,比如webapps,我们在外部放置项目,就自动同步内部就好了! 这同样使用到的是数据卷技术!


案例三:部署elasticsearch+kibana

shell 复制代码
# es 暴露的端口很多!
# es 十分耗内存
# es 的数据一般需要放置到安全目录!挂载
# --net somenetwork  网络配置

# 启动elasticsearch
[root@Mango ~]# docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2

# 测试一下es是否成功启动
➜  ~ curl localhost:9200
{
  "name" : "d73ad2f22dd3",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "atFKgANxS8CzgIyCB8PGxA",
  "version" : {
    "number" : "7.6.2",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
    "build_date" : "2020-03-26T06:34:37.794943Z",
    "build_snapshot" : false,
    "lucene_version" : "8.4.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

[root@Mango ~]# docker stats  # 显示正在运行的容器的实时资源使用情况 (查看内存使用情况)

#测试成功就关掉elasticSearch,防止耗内存
[root@Mango ~]# docker stop d834ce2bd306
d834ce2bd306
shell 复制代码
#测试成功就关掉elasticSearch,可以添加内存的限制,修改配置文件 -e选项:环境配置修改
#  -e ES_JAVA_OPTS="-Xms64m -Xmx512m  :最多只占512M空间
docker rm -f d73ad2f22dd3            # stop命令也行                               
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2
shell 复制代码
#进行本地测试:  curl localhost:9200
{
  "name" : "b72c9847ec48",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "yNAK0EORSvq3Wtaqe2QqAg",
  "version" : {
    "number" : "7.6.2",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
    "build_date" : "2020-03-26T06:34:37.794943Z",
    "build_snapshot" : false,
    "lucene_version" : "8.4.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

Portainer 可视化面板安装

  • portainer(先用这个)

  • Rancher(CI/CD再用 -持续集成持续交付)

什么是portainer?

Docker图形化界面管理工具!提供一个后台面板供我们操作!

shell 复制代码
# portainer安装命令
[root@Mango ~]# docker run -d -p 8088:9000 \
> --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

Unable to find image 'portainer/portainer:latest' locally
latest: Pulling from portainer/portainer
d1e017099d17: Pull complete 
a7dca5b5a9e8: Pull complete 
Digest: sha256:4ae7f14330b56ffc8728e63d355bc4bc7381417fa45ba0597e5dd32682901080
Status: Downloaded newer image for portainer/portainer:latest
81753869c4fd438cec0e31659cbed0d112ad22bbcfcb9605483b126ee8ff306d
1234567891011

测试访问: 外网:8088

  • 要使用本地的8088,前提是把阿里云的安全组打开,并且容器内的portainer也要在运行
  • 选择Local,进入之后的面板

镜像原理之联合文件系统

镜像是什么

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,镜像包含运行某个软件所需的所有内容,包括代码、运行时库、环境变量和配置文件。所有的应用,直接打包成docker镜像,就可以直接跑起来

如何得到镜像

  • 从远程仓库下载
  • 别人拷贝给你
  • 自己制作一个镜像 (需要使用DockerFile)

Docker镜像加载原理

UnionFs (联合文件系统)

UnionFs(联合文件系统):是一种分层、轻量级 并且高性能的文件系统,支持对文件系统的修改作为一次提交来一层层的叠加 ,同时可以将不同目录挂载到同一个虚拟文件系统下

UnionFS文件系统是 Docker镜像的基础,镜像可以通过分层来进行继承,基于基础镜像可以制作各种具体的应用镜像

特性:一次同时加载多个文件系统 ,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录

Docker镜像加载原理

docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统称为UnionFS

boots(boot file system)主要包含 bootloader和 Kernel, bootloader主要是引导加载kernel , Linux刚启动时会加bootfs文件系统,在 Docker镜像的最底层是 boots ,当boots加载完成之后整个内核就都在内存中了,此时内存的使用权已由 bootfs转交给内核,此时系统也会卸载bootfs

rootfs(root file system),在 bootfs之上,包含的就是典型 Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件,rootfs就是各种不同的操作系统发行版,比如 Ubuntu, Centos等等

内核 => 内核+image => 内核+image +image ,每一层不断的往上进行叠加

平时我们安装到虚拟机的CentOS都是好几个G,为什么Docker这里才200M

对于精简的OS,rootfs可以很小,只需要包合最基本的命令,工具和程序库就可以了,因为docker底层直接用宿主机的kernel,docker容器本身只需要提供rootfs就可以了,虚拟机是分钟级别启动,容器是秒级启动!

由此可见对于不同的Linux发行版, boots基本是一致的, rootfs会有差別,因此不同的发行版可以公用bootfs


分层理解

分层的镜像

我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层层的在下载

思考:为什么Docker镜像要采用这种分层的结构呢?

1.节省存储空间:分层结构允许镜像的不同层次之间共享相同的文件 (资源共享)

  • 对于多个镜像,如果它们具有相同的基础层,那么这些基础层只需要存储一次,从而节省了存储空间,这对于大规模部署和分布式系统尤其重要,因为可以减少大量相同文件的重复存储
  • 比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘当中保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享

2.加快镜像传输速度 :当需要从一个地方传输镜像到另一个地方时,分层结构使得只需传输有进行更改的层,而不需要传输整个镜像。这可以显著减少传输所需的时间和带宽消耗

3.提高镜像的可复用性 :分层结构使得镜像的不同层可以独立更新和管理,使得镜像更易于维护和更新

  • 通过修改和更新镜像的特定层,可以轻松创建新的镜像版本,而无需重新构建整个镜像

4.支持版本控制和回滚:通过分层结构,可以轻松管理和控制镜像的不同版本,这对于应用程序的持续集成和交付以及故障恢复非常有用

  • 每个层都可以被视为一个单独的版本,可以轻松地回滚到先前的版本或创建新的版本

5.支持容器快速启动和销毁:由于Docker容器的可写层是在镜像的顶部,容器的创建和销毁操作只涉及对这个可写层的修改,这使得容器的启动和销毁非常快速,因为只需要对可写层的变更进行操作,而不需要重新加载整个镜像

  • 在Docker中,容器的可写层是指容器运行时创建的可写文件系统层 。该层位于镜像的顶部,用于存储容器运行时的变化和数据 。当容器创建时,Docker会在镜像的基础上添加一个可写层,用于记录容器中的文件修改、新增和删除等操作
  • 由于可写层是容器独有的 ,而镜像的其余部分是只读的 ,因此在容器的启动和销毁过程中,只需要对可写层进行修改和操作,而无需重新加载整个镜像,这种设计使得容器的启动和销毁操作非常快速
    • 当启动容器时,Docker只需要加载基础镜像的只读部分和可写层,而不需要重新加载整个镜像。只有在镜像不存在本地时,Docker才会下载整个镜像,这种加载方式使得容器的启动速度更快,并且占用更少的存储空间
      • 在容器启动时,Docker会创建一个只读的文件系统,其中包含基础镜像的只读部分,这些只读部分通常是共享的,即多个容器可以共享相同的只读部分
    • 当销毁容器时,只需要清理掉容器的可写层,而不需要涉及整个镜像的操作
  • 这种可写层的机制使得容器可以快速启动和销毁,非常适合动态扩展和快速部署的场景。它也提供了容器间的隔离性,每个容器都有自己的可写层,互不干扰
  • 由于可写层的存在,如果频繁修改容器中的文件,可写层可能会随着时间增长而增大。这在一定程度上会对存储空间产生影响。因此,在设计容器应用时,需要注意避免不必要的文件修改,或者使用持久化卷等机制来存储需要保留的数据,以减小可写层的大小

查看镜像分层命令

bash 复制代码
docker image inspect 镜像id/镜像名字

实例理解分层

所有的 Docker镜像都起始于一个基础镜像层,当进行修改或培加新的内容时,就会在当前镜像层之上,创建新的镜像层

举一个简单的例子

1)假如基于 Ubuntu Linux16.04创建一个新的镜像,这就是新镜像的第一层

2)如果在该镜像中添加 Python包,就会在基础镜像层之上创建第二个镜像层

3)如果继续添加一个安全补丁,就会创建第三个镜像层该像当前已经包含3个镜像层

在添加额外的镜像层的同时,镜像始终保持是当前所有"镜像层"的组合!!!


下图中举了一个简单的例子,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件


下图中展示了一个稍微复杂的三层镜像,因为最上层中的文件7是文件5的一个更新版,那么在外部看来整个镜像只有6个文件

这种情況下,上层镜像层中的文件覆盖了底层镜像层中的文件,这样就使得文件的更新版本作为一个新镜像层添加到镜像当中


Docker通过存储引擎(新版本采用快照机制 )的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统

  • 下图展示了与系统显示相同的三层镜像。所有镜像层堆并合井,对外提供统一的视图

特点

Docker 镜像都是只读的,当容器启动时,一个新的可写层会加载到镜像的顶部!这一层就是通常说的容器层,容器之下的都叫镜像层!

案例:做一个镜像

提交容器成为新镜像的命令

shell 复制代码
docker commit #提交容器成为一个新的镜像

# 命令和git原理类似
docker commit -m="描述信息" -a="作者" 容器id 目标镜像名:[版本TAG]

实战测试

shell 复制代码
# 1、启动一个默认的tomcat
[root@Mango ~]# docker run -d -p 8080:8080 tomcat
de57d0ace5716d27d0e3a7341503d07ed4695ffc266aef78e0a855b270c4064e

# 2、这个默认启动的tomcat 是没有webapps应用,因为下载docker的时候使用的是阿里云的镜像,而阿里云默认是最小的镜像,所以不必要的内容都剔除掉,保证最小可运行的环境! 阿里云官方的镜像默认webapps文件夹是没有文件的
#docker exec -it 容器id /bin/bash  进入tomcat控制台
[root@Mango ~]# docker exec -it de57d0ace571 /bin/bash
root@de57d0ace571:/usr/local/tomcat#  

# 3、从webapps.dist拷贝文件进去webapp
root@de57d0ace571:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@de57d0ace571:/usr/local/tomcat# cd webapps
root@de57d0ace571:/usr/local/tomcat/webapps# ls
ROOT  docs  examples  host-manager  manager

# 4、将操作过的容器通过commit调整为一个镜像!我们以后就使用我们修改过的镜像即可,而不需要每次都重新拷贝webapps.dist下的文件到webapps了,这就是我们自己的一个修改的镜像。
#docker commit -m="描述信息" -a="作者" 容器id 目标镜像名:[TAG]
docker commit -a="Mango" -m="add webapps app" 原来的容器id tomcat02:1.0

[root@Mango ~]# docker commit -a="csp提交的" -m="add webapps app" de57d0ace571 tomcat02.1.0
sha256:d5f28a0bb0d0b6522fdcb56f100d11298377b2b7c51b9a9e621379b01cf1487e

[root@Mango ~]# docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
tomcat02.1.0          latest              d5f28a0bb0d0        14 seconds ago      652MB #发现比原来的版本更大
tomcat                latest              1b6b1fe7261e        5 days ago          647MB
nginx                 latest              9beeba249f3e        5 days ago          127MB
mysql                 5.7                 b84d68d0a7db        5 days ago          448MB
elasticsearch         7.6.2               f29a1ee41030        8 weeks ago         791MB
portainer/portainer   latest              2869fc110bf7        2 months ago        78.6MB
centos                latest              470671670cac        4 months ago        237MB
hello-world           latest              bf756fb1ae65        4 months ago        13.3kB

如果你想要保存当前容器的状态,就可以通过commit来提交,从而获得一个镜像,就好比我们我们使用虚拟机的快照

相关推荐
小安运维日记31 分钟前
Linux云计算 |【第四阶段】NOSQL-DAY1
linux·运维·redis·sql·云计算·nosql
m0_741768854 小时前
使用docker的小例子
运维·docker·容器
学习3人组5 小时前
CentOS 中配置 OpenJDK以及多版本管理
linux·运维·centos
厨 神5 小时前
vmware中的ubuntu系统扩容分区
linux·运维·ubuntu
Karoku0665 小时前
【网站架构部署与优化】web服务与http协议
linux·运维·服务器·数据库·http·架构
geek_Chen015 小时前
虚拟机共享文件夹开启后mnt/hgfs/下无sharefiles? --已解决
linux·运维·服务器
(⊙o⊙)~哦6 小时前
linux 解压缩
linux·运维·服务器
最新小梦7 小时前
Docker日志管理
运维·docker·容器
鸡鸭扣8 小时前
虚拟机:3、(待更)WSL2安装Ubuntu系统+实现GPU直通
linux·运维·ubuntu
友友马8 小时前
『 Linux 』HTTP(一)
linux·运维·服务器·网络·c++·tcp/ip·http