Docker 的安装 查看系统信息 目前,CentOS 仅发行版本中的内核支持 Docker。Docker 运行在 CentOS 7 上,要求系统为64位、系统内核版本为 3.10 以上。 查看自己的内核:
uname -r
命令用于打印当前系统相关信息(内核版本号、硬件架构、主机名称和操作系统类型 等)。
1 2 [root@ls-rK8rbuXz ~]# uname -r 3.10.0-1160.62.1.el7.x86_64
查看版本信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [root@ls-rK8rbuXz ~] 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"
安装步骤 官网安装参考手册: https://docs.docker.com/engine/install/centos/
Centos 安装
确定你是CentOS7及以上版本,我们已经做过了
yum安装gcc相关环境(需要确保 虚拟机可以上外网 )
卸载旧版本
1 2 3 4 5 6 7 8 yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine
安装需要的软件包
设置镜像仓库
1 2 3 4 5 6 yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo [Errno 14] curl yum-config-manager --add-repo http://mirrors.aliyun.com/docker- ce/linux/centos/docker-ce.repo
更新yum软件包索引
安装 Docker CE(社区版)
启动 Docker
测试命令
1 2 3 root@ls-rK8rbuXz:~ root@ls-rK8rbuXz:~ root@ls-rK8rbuXz:~
卸载
1 2 3 root@ls-rK8rbuXz:~ root@ls-rK8rbuXz:~ root@ls-rK8rbuXz:~
Ubuntu 安装 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add - echo 'deb https://mirrors.aliyun.com/docker-ce/linux/debian buster stable' > /etc/apt/sources.list.d/docker.listapt update apt remove docker docker-engine docker.io apt install docker-ce docker version
阿里云镜像加速
介绍: https://www.aliyun.com/product/acr
注册一个属于自己的阿里云账户(可复用淘宝账号)
进入管理控制台设置密码,开通
查看镜像加速器自己的
1 2 3 4 5 6 7 8 9 10 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors" : ["https://htouo715.mirror.aliyuncs.com" ] } EOF sudo systemctl daemon-reload sudo systemctl restart docker
测试获取hello-word镜像
运行 hello-world
镜像
run 做了什么?
底层原理 Docker是怎么工作的
Docker是一个Client-Server结构的系统,Docker守护进程运行在主机上, 然后通过Socket连接从客户 端访问,守护进程从客户端接受命令并管理运行在主机上的容器。 容器,是一个运行时环境,就是我们 前面说到的集装箱。
为什么 Docker 比 VM 快
1、docker有着比虚拟机更少的抽象层。由亍docker不需要Hypervisor实现硬件资源虚拟化,运行在 docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在 效率上有明显优势。
2、docker利用的是宿主机的内核,而不需要Guest OS。因此,当新建一个容器时,docker不需要和虚拟机 一样重新加载一个操作系统内核。仍而避免引寻、加载操作系统内核返个比较费时费资源的过程,当新建 一个虚拟机时,虚拟机软件需要加载Guest OS,返个新建过程是分钟级别的。而docker由于直接利用宿主 机的操作系统,则省略了返个过程,因此新建一个docker容器只需要几秒钟。
Docker 常用命令
帮助命令 0111
1 2 3 4 5 docker version docker version docker info docker --help docker 命令 --help
镜像命令 docker images
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 [root@ls-rK8rbuXz ~] REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest feb5d9fea6a5 21 months ago 13.3kB REPOSITORY TAG IMAGE ID CREATED SIZE -a: 列出本地所有镜像 -q: 只显示镜像id --digests: 显示镜像的摘要信息
docker search
1 2 3 4 5 6 7 8 9 10 11 [root@ls-rK8rbuXz ~] NAME DESCRIPTION STARS OFFICIAL AUTOMATED mysql MySQL is a widely used, open-source relation… 14274 [OK] mariadb MariaDB Server is a high performing open sou… 5455 [OK] percona Percona Server is a fork of the MySQL relati… 617 [OK] phpmyadmin phpMyAdmin - A web interface for MySQL and M… 831 [OK] --filter=stars=50
docker pull
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 [root@ls-rK8rbuXz ~] Using default tag: latest latest: Pulling from library/mysql 72a69066d2fe: Pull complete 93619dbc5b36: Pull complete 99da31dd6142: Pull complete 626033c43d70: Pull complete 37d5d7efb64e: Pull complete ac563158d721: Pull complete d2ba16033dad: Pull complete 688ba7d5c01a: Pull complete 00e060b6d11d: Pull complete 1c04857f594f: Pull complete 4d7cfa90e6ea: Pull complete e0431212d27d: Pull complete Digest: sha256:e9027fe4d91c0153429607251656806cc784e914937271037f7738bd5b8e7709 Status: Downloaded newer image for mysql:latest docker.io/library/mysql:latest [root@ls-rK8rbuXz ~]
docker rmi
1 2 3 4 5 docker rmi 镜像id 或镜像名 dokcer rmi -f 镜像id 或镜像名 docker rmi -f 镜像名(id ):tag 镜像名(id ):tg docker rmi -f $(docker images -aq)
容器命令 说明:有镜像才能创建容器,我们这里使用 centos
的镜像来测试,就是虚拟一个 centos !
新建容器并启动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 docker run [OPTIONS] IMAGE [COMMAND][ARG...] --name="containerName" -d -i -t -P -p ip:主机的端口:容器端口 ip::容器端口 主机端口:容器端口(常用) 容器端口 [root@ls-rK8rbuXz ~] REPOSITORY TAG IMAGE ID CREATED SIZE mysql 5.7 c20987f18b13 18 months ago 448MB mysql latest 3218b38490ce 18 months ago 516MB centos latest 5d0da3dc9764 21 months ago 231MB [root@ls-rK8rbuXz ~] [root@ls-rK8rbuXz ~] [root@ec124b7f2cf0 /] [root@ec124b7f2cf0 /] [root@ec124b7f2cf0 /] bin etc lib lost+found mnt proc run srv tmp var dev home lib64 media opt root sbin sys usr [root@ec124b7f2cf0 /] [root@ec124b7f2cf0 /] exit [root@ls-rK8rbuXz ~]
列出所有运行的容器
1 2 3 4 5 6 7 8 docker ps [OPTIONS] -a -l -n=number -q
退出容器
启动停止容器
1 2 3 4 docker start 容器id 或容器名 docker restart 容器id 或容器名 docker stop 容器id 或容器名 docker kill 容器id 或容器名
删除容器
1 2 3 4 docker rm 容器id或容器名 # 删除一个停止的容器 docker rm -f 容器id或容器名 # 强制删除一个容器(包括正在运行的容器) docker rm -f $(docker ps -qa) # 强制删除所有容器(包括正在运行的容器) dokcer ps -qa | xargs docker rm -f # 强制删除所有容器(包括正在运行的容器)
其他常用命令 后台启动容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 docker run -d 镜像名 docker run -d centos [root@ls-rK8rbuXz ~] CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6f655e268f0e centos "/bin/bash" 2 seconds ago Exited (0) 2 seconds ago hungry_hamilton [root@ls-rK8rbuXz ~] [root@ls-rK8rbuXz ~] f4911c07c121b70bde41bfcd84128d53640f3416f8e4be71c8c3372242cbea79 [root@ls-rK8rbuXz ~] CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f4911c07c121 centos "/bin/bash" 1 second ago Up 1 second suspicious_jackson
查看日志
1 2 3 4 5 6 7 8 9 10 11 12 13 -f 滚动日志 实时刷新 -t 显示时间 -n 显示的行数 (默认不指定显示所有) docker run -d centos /bin/sh -c "while true;do echo x1ong;sleep 1;done" [root@ls-rK8rbuXz ~] 2023-07-04T07:49:48.107583028Z x1ong 2023-07-04T07:49:49.109597644Z x1ong
查看容器中运行的进程信息
1 2 3 4 5 6 docker top 容器id [root@ls-rK8rbuXz ~] UID PID PPID C STIME TTY TIME CMD root 19996 19974 0 15:53 pts/0 00:00:00 /bin/bash
查看容器/镜像的元数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 docker inspect 容器ID [root@ls-rK8rbuXz ~] [ ....... "Networks" : { "bridge" : { "Gateway" : "172.17.0.1" , "IPAddress" : "172.17.0.2" , .... } } ]
进入正在运行的容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 docker exec -it 容器id bashShell [root@ls-rK8rbuXz ~] CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES dfd8e5a602b9 centos "/bin/bash" 5 minutes ago Up 5 minutes nostalgic_wilson [root@ls-rK8rbuXz ~] [root@dfd8e5a602b9 /] dfd8e5a602b9 docker attach 容器id [root@ls-rK8rbuXz ~] CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES dfd8e5a602b9 centos "/bin/bash" 6 minutes ago Up 5 minutes nostalgic_wilson [root@ls-rK8rbuXz ~] [root@dfd8e5a602b9 /] dfd8e5a602b9
从容器内复制文件到宿主机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 docker cp 容器id :容器内路径 目的主机路径 [root@dfd8e5a602b9 ~] [root@dfd8e5a602b9 home] [root@dfd8e5a602b9 home] helloworld [root@dfd8e5a602b9 home] [root@ls-rK8rbuXz ~] Successfully copied 2.05kB to /tmp/123.txt [root@ls-rK8rbuXz ~] [root@ls-rK8rbuXz ~] helloworld [root@ls-rK8rbuXz ~]
安装练习 使用 docker 安装 nginx 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 [root@ls-rK8rbuXz ~] NAME DESCRIPTION STARS OFFICIAL AUTOMATED nginx Official build of Nginx. 18715 [OK] ... [root@ls-rK8rbuXz ~] [root@ls-rK8rbuXz ~] REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 605c77e624dd 18 months ago 141MB [root@ls-rK8rbuXz ~] a7b3aafe7ae6add22d680848ace975c726523828abd08752867003f376998500 [root@ls-rK8rbuXz ~] CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a7b3aafe7ae6 nginx "/docker-entrypoint.…" 3 seconds ago Up 2 seconds 0.0.0.0:8080->80/tcp, :::8080->80/tcp nginx01 [root@ls-rK8rbuXz ~] ... <h1>Welcome to nginx!</h1> .... [root@ls-rK8rbuXz ~] root@a7b3aafe7ae6:/ bin dev docker-entrypoint.sh home lib64 mnt proc run srv tmp var boot docker-entrypoint.d etc lib media opt root sbin sys usr root@a7b3aafe7ae6:/ nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx root@a7b3aafe7ae6:/ root@a7b3aafe7ae6:/usr/share/nginx html root@a7b3aafe7ae6:/usr/share/nginx root@a7b3aafe7ae6:/usr/share/nginx/html 50x.html index.html root@a7b3aafe7ae6:/usr/share/nginx/html ... <h1>Welcome to nginx!</h1> ...
使用 docker 安装 tomcat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 [root@ls-rK8rbuXz ~] [root@ls-rK8rbuXz ~] REPOSITORY TAG IMAGE ID CREATED SIZE tomcat latest fb5657adc892 18 months ago 680MB [root@ls-rK8rbuXz ~] 1fde810bfc6d5d629c2cd67def8d32bc93fa92eb320b2379e7d59bdcd9507dcb [root@ls-rK8rbuXz ~] CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1fde810bfc6d tomcat "catalina.sh run" 3 seconds ago Up 2 seconds 0.0.0.0:8081->8080/tcp, :::8081->8080/tcp tomcat01 [root@ls-rK8rbuXz ~] ... <h1>HTTP Status 404 – Not Found</h1> ... [root@ls-rK8rbuXz ~] CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1fde810bfc6d tomcat "catalina.sh run" 2 minutes ago Up 2 minutes 0.0.0.0:8081->8080/tcp, :::8081->8080/tcp tomcat01 [root@ls-rK8rbuXz ~] root@1fde810bfc6d:/usr/local/tomcat BUILDING.txt LICENSE README.md RUNNING.txt conf logs temp webapps.dist CONTRIBUTING.md NOTICE RELEASE-NOTES bin lib native-jni-lib webapps work root@1fde810bfc6d:/usr/local/tomcat root@1fde810bfc6d:/usr/local/tomcat/webapps
docker 镜像 镜像的概念
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含 运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
docker 镜像加载原理
UnionFS (联合文件系统)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统, 它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系 统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基 础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件 系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
Docker镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启 动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是 一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已 由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标 准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
平时我们安装进虚拟机的CentOS都是好几个G,为什么Docker这里才200M?
对于一个精简的OS,rootfs
可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直 接用Host的kernel,自己只需要提供rootfs
就可以了。由此可见对于不同的linux发行版, bootfs基本是一 致的, rootfs会有差别, 因此不同的发行版可以公用bootfs
。
分层理解
分层的镜像
我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层一层的在下载!
思考:为什么Docker
镜像要采用这种分层的结构呢?
最大的好处,我觉得莫过于是资源共享了!比如有多个镜像都从相同的Base
镜像构建而来,那么宿主机 只需在磁盘上保留一份base
镜像,同时内存中也只需要加载一份base
镜像,这样就可以为所有的容器服 务了,而且镜像的每一层都可以被共享。
查看镜像分层的方式可以通过 docker image inspect 镜像名称:tag
命令!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 [root@ls-rK8rbuXz ~] [ ... "RootFS" : { "Type" : "layers" , "Layers" : [ "sha256:2edcec3590a4ec7f40cf0743c15d78fb39d8326bc029073b41ef9727da6c851f" , "sha256:9b24afeb7c2f21e50a686ead025823cd2c6e9730c013ca77ad5f115c079b57cb" , "sha256:4b8e2801e0f956a4220c32e2c8b0a590e6f9bd2420ec65453685246b82766ea1" , "sha256:529cdb636f61e95ab91a62a51526a84fd7314d6aab0d414040796150b4522372" , "sha256:9975392591f2777d6bf4d9919ad1b2c9afa12f9a9b4d260f45025ec3cc9b18ed" , "sha256:8e5669d8329116b8444b9bbb1663dda568ede12d3dbcce950199b582f6e94952" ] }, "Metadata" : { "LastTagTime" : "0001-01-01T00:00:00Z" } ]
理解:
所有的 Docker
镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之 上,创建新的镜像层。
举一个简单的例子,假如基于 Ubuntu Linux 16.04
创建一个新的镜像,这就是新镜像的第一层;如果 在该镜像中添加 Python
包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就 会创建第三个镜像层。
该镜像当前已经包含 3 个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了 一个简单的例子,每个镜像层包含 3 个文件,而镜像包含了来自两个镜像层的 6 个文件。
上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有 6 个文件,这是因为最上层中的文件 7 是文件 5 的一个更新版本。
这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新 镜像层添加到镜像当中。
Docker 通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统 一的文件系统。
Linux 上可用的存储引擎有 AUFS、Overlay2、Device Mapper、Btrfs 以及 ZFS。顾名思义,每种存储 引擎都基于 Linux 中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。
Docker 在 Windows 上仅支持 windowsfilter 一种存储引擎,该引擎基于 NTFS 文件系统之上实现了分 层和 CoW[1]。
下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。
特点:
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部! 这一层就是我们通常说的容器层,容器之下的都叫镜像层!
镜像 commit
docker commit 从容器创建一个新的镜像。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 docker commit docker commit -m="镜像的描述信息" -a="镜像的作者" 容器id 要目标镜像名:[标签名] docker commit -m="add webapps content" -a="x1ong" fb5657adc892 tomcat01:1.0 [root@ls-rK8rbuXz ~] cef950c16d35c2ba6d8df63e374e7397f5a1fc56e023aa77706e823701d515ee [root@ls-rK8rbuXz ~] CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES cef950c16d35 tomcat "catalina.sh run" 4 seconds ago Up 3 seconds 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp epic_bardeen [root@ls-rK8rbuXz ~] root@cef950c16d35:/usr/local/tomcat root@cef950c16d35:/usr/local/tomcat exit [root@ls-rK8rbuXz ~] [root@ls-rK8rbuXz ~] sha256:3a57775fb4c30d47516af74177fbeab4d4753874497996c4e91ef73474a2f42e [root@ls-rK8rbuXz ~] REPOSITORY TAG IMAGE ID CREATED SIZE tomcat01 0.1 3a57775fb4c3 2 seconds ago 684MB tomcat latest fb5657adc892 18 months ago 680MB [root@ls-rK8rbuXz ~] 1422dd48f25e63307038a0137af3f2a5aa96cab2ea99490006c077a5baf51e79 [root@ls-rK8rbuXz ~] root@1422dd48f25e:/usr/local/tomcat root@1422dd48f25e:/usr/local/tomcat/webapps
如果你想要保存你当前的状态,可以通过commit,来提交镜像,方便使用,类似于 VM 中的快照!
容器数据卷 Docker 的理念回顾 将应用和运行的环境打包形成镜像,在 docker 中进行运行,此时数据是存在容器中的,当我们把容器删除,那么容器中的数据就会随之删除。
如果我们想要持久化存储数据,那么当容器被删除的时候,数据也会丢失。
为了能让我们的数据持久化存储,这里就需要用到 Docker 的容器卷技术。
Docker 的容器数据卷 Docker 容器卷技术就是 将容器的某个文件夹或文件挂载到宿主机的某个文件夹或文件当中,当容器的文件夹的内容被修改,那么宿主机中的文件夹内容也会随之修改,保持同步的状态 。
作用:
卷就是目录或者文件,存在一个或者多个容器中,由docker挂载到容器,但不属于联合文件系统,因此 能够绕过 Union File System , 提供一些用于持续存储或共享数据的特性:
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此 Docker不会在容器删除时删除其挂载的数据卷。
特点:
1、数据卷可在容器之间共享或重用数据 2、卷中的更改可以直接生效 3、数据卷中的更改不会包含在镜像的更新中 4、数据卷的生命周期一直持续到没有容器使用它为止
所以: 总结一句话: 就是容器的持久化,以及容器间的继承和数据共享!
使用数据卷 使用 docker 中的 -v
参数可以绑定容器卷
1 2 root@ls-rK8rbuXz:~ -v, --volume list Bind mount a volume
挂载命令的使用:
1 2 3 4 docker run -it -d -v 宿主机绝对路径目录:容器内目录 镜像名 docker run -it -d -v /home/data:/home centos /bin/bash
查看是否挂载成功:
1 2 3 4 5 6 7 8 9 10 11 12 root@ls-rK8rbuXz:~ ... "Mounts" : [ { "Type" : "bind" , "Source" : "/home/data" , "Destination" : "/home" , "Mode" : "" , "RW" : true , "Propagation" : "rprivate" } ...
测试容器和宿主机之间数据共享:可以发现,在容器中创建的,会在宿主机中看到。
测试容器停止退出后,主机修改数据是否会同步:
停止容器
在宿主机上修改文件,增加些内容
启动刚才停止的容器
然后查看对应的文件,发现数据依旧同步!ok
实战
使用 docker 安装 mysql
要求:将容器内 mysql数据库的数据 使用容器数据卷技术 挂载到宿主机中。
1 2 3 4 5 6 root@ls-rK8rbuXz:~ root@ls-rK8rbuXz:~ root@ls-rK8rbuXz:/home
此时容器中的 /etc/mysql/conf.d
、/var/lib/mysql
目录就分别挂载到了宿主机的 /home/mysql/conf
和 /home/mysql/data
目录下。
DockerFile 前置知识 这里我们思考一个问题,我们常常使用 docker pull
去拉取一个镜像的时候,那么这个镜像是怎么来的?答案是官方有内置的镜像,比如 apache、nginx、redis、tomcat 等。
当然,这里我们普通用户其实也是可以上传直接的 docker 镜像的。
从编写 DockFile 到上传镜像 和 启动运行 流程大概是这样的:
开始应用 => 编写DockerFile => 打包为镜像 => 上传到仓库(私有仓库 or 公有仓库) => 下载镜像 => 启动运行。
DockerFile 的概念 DockerFile 是用来构建 Docker 镜像的文件,是由一系列命令和参数构成的脚本。
构建步骤:
编写 DockerFile 文件
docker build 构建镜像
docker run 启动运行
这里我们来看下 centos 镜像的 DockerFile 文件:https://hub.docker.com/_/centos
DockerFile 构建过程 基础知识
每条保留字指令都必须为大写 且 后面要跟随至少一个参数
指令按照从上到下,顺序执行。
#
表示注释
每条指令都会创建一个新的镜像层,并对镜像进行提交
流程
docker从基础镜像运行一个容器
执行一条指令并对容器做出修改
执行类似 docker commit
的操作提交一个新的镜像层
docker 在基于刚提交的镜像运行一个新的容器
执行DockerFile中的下一条指令直到所有指令都执行完成!
说明 从软件开发的角度来看,DockerFile、Docker镜像、Docker容器分别代表了三个不同的阶段:
DockerFile 就是软件的原材料(代码)
Docker 镜像则是软件的交付品(.apk)
Docker 容器则是软件的运行状态(客户下载安装执行)
构建命令
编写Dockerfile:文件名随意,但是官方推荐命令为:Dockerfle
构建镜像:docker build -t 镜像名:TAG -f Dockerfile文件名
如果是默认文件名则为:docker build -t 镜像名:TAG .
运行镜像:docker run -itd -p 宿主机端口:容器端口 镜像名:TAG /bin/bash
DockerFile 指令 1 2 3 4 5 6 7 8 9 10 11 12 FROM MAINTAINER RUN EXPOSE WORKDIR ENV ADD COPY VOLUME CMD ENTRYPOINT ONBUILD
实战测试
Docker Hub 中99% 的镜像都是通过在base镜像 (Scratch) 中安装和配置需要的软件构建出来的。
构建 Centos 要求该容器安装 vim
、net-tools
、apache
软件。
编写 Dockerfile 在当前目录下创建文件 Dockerfile 内容如下:
1 2 3 4 5 6 7 8 9 10 FROM centos:7 MAINTAINER x1ongsec<x1ongsec@163 .com>ENV wwwroot /var/www/html/WORKDIR $wwwroot RUN /bin/bash RUN yum install vim -y RUN yum install net-tools -y RUN yum install httpd -y EXPOSE 80 CMD ["/bin/bash" ]
构建镜像
接着使用 docker images
查看镜像会发现多个 centos_base
1 2 3 4 5 6 7 root@ls-rK8rbuXz:~ REPOSITORY TAG IMAGE ID CREATED SIZE centos_base latest df0c8ace1444 9 hours ago 904MB mysql latest c138801544a9 2 months ago 577MB centos latest 5d0da3dc9764 2 years ago 231MB medicean/vulapps base_lamp f4e50ddb88a4 5 years ago 602MB root@ls-rK8rbuXz:~
镜像运行测试 1 2 root@ls-rK8rbuXz:~ d4577993b09202dac661946fc798c7029ae6ab7fe2a5222d8fc837f87cb0966a
进入到容器:
1 2 3 4 5 6 7 8 9 10 11 12 root@ls-rK8rbuXz:~ [root@d4577993b092 html] vim-common-7.4.629-8.el7_9.x86_64 vim-enhanced-7.4.629-8.el7_9.x86_64 httpd-tools-2.4.6-99.el7.centos.1.x86_64 vim-minimal-7.4.629-7.el7.x86_64 vim-filesystem-7.4.629-8.el7_9.x86_64 net-tools-2.0-0.25.20131004git.el7.x86_64 httpd-2.4.6-99.el7.centos.1.x86_64 [root@d4577993b092 html]
列出镜像的变更历史 1 2 docker history 镜像名 or 镜像ID
构建 Tomcat 要求:使用 Centos7 基础镜像,并在该镜像上安装必要的vim
、net-tools
以及程序 tomcat
和其依赖环境 jdk
准备工作 这里我们需要在tomcat的官网以及jdk的官网下载两者的二进制执行文件:
Tomcat 官网:https://tomcat.apache.org
Jdk 官网:https://www.oracle.com/java/technologies/downloads/#java8
准备文件如下,其中 README.txt
则是对本镜像的说明,内容自己填写。
编写 Dockerfile 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 FROM centos:7 MAINTAINER x1ongsec<x1ongsec@163.com> COPY README.txt /root ADD apache-tomcat-9.0.81.tar.gz /usr/local ADD jdk-8u381-linux-x64.tar.gz /usr/local RUN /bin/bash RUN yum install vim -y RUN yum install net-tools -y ENV MYPATH /usr/local WORKDIR $MYPATH ENV JAVA_HOME /usr/local/jdk1.8.0_381 ENV CLASSPATH ${JAVA_HOME} /lib/dt.jar:${JAVA_HOME} /lib/tools.jar ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.81 ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.81 ENV PATH $PATH :$JAVA_HOME /bin:$CATALINA_HOME /lib:$CATALINA_HOME /bin EXPOSE 8080 ENTRYPOINT ["/usr/local/apache-tomcat-9.0.81/bin/catalina.sh" , "run" ]
构建镜像 1 root@ls-rK8rbuXz:~/tomcat
镜像运行测试 1 2 root@ls-rK8rbuXz:~ fc5dbd0c5ee8b65f008fd93786baff5899e451b5f00369923094927c102d47f8
访问测试
CMD 与ENTRYPOINT 的区别 CMD CMD 指令为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。 类似于 RUN 指令,用于运行程序,但二者运行的时间点不同: CMD 在docker run 时运行,RUN 是在 docker build时运行。 注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
ENTRYPOINT 类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
但是, 如果运行 docker run 时使用了 –entrypoint 选项,将覆盖 ENTRYPOINT 指令指定的程序。 优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
CMD测试 CMD什么时候执行 建一个简单的 Dockerfile 文件,内容为下面的2行内容:
1 2 FROM centos:7 CMD ["ls" ,"-s" ]
使用如下的命令,建造一个镜像并使用镜像建一个容器:
1 2 root@ls-rK8rbuXz:~ root@ls-rK8rbuXz:~
可以看到,容器运行起来后直接运行了CMD中的命令。也就是说CMD在镜像运行的时候执行。
覆盖CMD的命令 使用下面的命令运行一个容器,可以看到已经覆盖了CMD设置的命令
ENTRYPOINT测试 ENTRYPOINT什么时候执行 建一个简单的 Dockerfile 文件,内容为下面的2行内容:
1 2 FROM centos:7 ENTRYPOINT ["ls" ,"-s" ]
建造一个镜像并使用镜像建一个容器
运行后和默认的和CMD是一样的
ENTRYPOINT设置的指令后面追加指令 使用 docker run 377bed257c25 -l
看到 -l
已经追加到dockerfile
设置的指令后面并执行了。
总结
CMD设置的指令在镜像运行时自动运行,无法追加指令,只能把指令全部覆盖。
ENTRYPOINT设置的指令在镜像运行时与CMD一样,可以在新建镜像时设置的指令后追加新的指令,也可以使用 –entrypoint 覆盖指令。
发布镜像到DockerHub 注册DockerHub https://hub.docker.com/signup,需要有一个账号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 root@ls-rK8rbuXz:~ Usage: docker login [OPTIONS] [SERVER] Log in to a registry. If no server is specified, the default is defined by the daemon. Options: -p, --password string Password --password-stdin Take the password from stdin -u, --username string Username root@ls-rK8rbuXz:~ Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/ Login Succeeded root@ls-rK8rbuXz:~ The push refers to repository [docker.io/library/tomcat_base] 5f70bf18a086: Preparing 9d3e7e13e895: Preparing 108c449d4d0d: Preparing 44754636ad15: Preparing 85d5b7f528b0: Preparing aca9902b61fd: Waiting b63e96353fcf: Waiting 174f56854903: Waiting denied: requested access to the resource is denied root@ls-rK8rbuXz:~ root@ls-rK8rbuXz:~ The push refers to repository [docker.io/x1ongsec/tomcat_base] 5f70bf18a086: Pushed 9d3e7e13e895: Pushed 108c449d4d0d: Pushed 44754636ad15: Pushed 85d5b7f528b0: Pushed aca9902b61fd: Pushed b63e96353fcf: Pushed 174f56854903: Pushed 1.0: digest: sha256:538c343e5d96a01cfeae635a98a1dd29dc5759384629d326b826ed53199c7260 size: 1997
Docker 网络 Docker 网络讲解 理解 Docker0 准备工作:清空所有的容器,清空所有的镜像
1 2 docker rm -f $(docker ps -a -q) docker rmi -f $(docker images -qa)
通信测试 这里我们先做一个测试
使用 ip addr
命令查看 Linux 服务器的网络信息:
这里我们分析可得,有三个网络:
127.0.0.1 本机回环地址
192.168.0.4 百度云服务器的内网IP
172.17.0.1 Docker 网桥
当我们创建一个容器的时候,docker会自动的为该容器分配一个IP地址,而该IP地址与Linux服务器的网桥IP同在一个网段。
这里思考一个问题:Linux服务器是否可以ping通容器?
答案是可以的。
第二个问题:容器是否可以ping通Linux网桥的IP以及Linux服务器的其他网卡?
答案也是可以的。
通信原理
每一个安装了 Docker 的 linux 主机都有一个 docker0 的虚拟网卡。这是个桥接网卡,使用了veth-pair
技术。
当我们运行一个容器之后,我们再次在Linux服务器中查看IP地址:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 root@ls-rK8rbuXz:~ 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link /loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link /ether fa:20:20:24:5d:41 brd ff:ff:ff:ff:ff:ff inet 192.168.0.4/20 brd 192.168.15.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::f820:20ff:fe24:5d41/64 scope link valid_lft forever preferred_lft forever 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link /ether 02:42:0a:b3:91:36 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:aff:feb3:9136/64 scope link valid_lft forever preferred_lft forever 241: vethd2cd09c@if240: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link /ether 96:55:a0:df :46:a6 brd ff:ff:ff:ff:ff:ff link-netnsid 1 inet6 fe80::9455:a0ff:fedf:46a6/64 scope link valid_lft forever preferred_lft forever
在没有开启任何容器之前我们有三个网络,分别是 lo
、eth0
、docker0
,但是当我们开启容器之后会多了个 vethd2cd09c@if240
的网络。
2、每启动一个容器,linux主机就会多了一个虚拟网卡。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [root@kuangshen ~] [root@kuangshen ~]
3、我们来测试下tomcat01和tomcat02容器间是否可以互相ping通
1 2 3 4 5 6 7 root@ls-rK8rbuXz:~ PING 172.17.0.3 (172.17.0.4) 56(84) bytes of data. 64 bytes from 172.17.0.4: icmp_seq=1 ttl=64 time=0.031 ms 64 bytes from 172.17.0.4: icmp_seq=2 ttl=64 time=0.037 ms 64 bytes from 172.17.0.4: icmp_seq=3 ttl=64 time=0.033 ms 64 bytes from 172.17.0.4: icmp_seq=4 ttl=64 time=0.033 ms
4、我们来绘制一个网络模型图
结论:tomcat1和tomcat2共用一个路由器。是的,他们使用的一个,就是docker0。任何一个容器启动 默认都是docker0网络。 docker默认会给容器分配一个可用ip。
小结 Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据 Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
Docker容器网络就很好的利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
Docker中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高(因为Linux是在内核中 进行数据的复制来实现虚拟接口之间的数据转发,无需通过外部的网络设备交换),对于本地系统和容器系统来说,虚拟接口跟一个正常的以太网卡相比并没有区别,只是他的速度快很多。
–Link 思考一个场景,我们编写一个微服务,数据库连接地址原来是使用ip的,如果ip变化就不行了,那我们能不能使用服务名访问呢?
jdbc:mysql://mysql:3306
,这样的话哪怕mysql重启,我们也不需要修改配置了! docker提供了 –link 的操作!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 root@ls-rK8rbuXz:~ ping: tomcat: Name or service not known root@ls-rK8rbuXz:~ d87cac2a282dbde98b2fb112d697e6e427611bb1ed87cd275d2ffb2617b34aff root@ls-rK8rbuXz:~ PING tomcat02 (172.17.0.4) 56(84) bytes of data. 64 bytes from tomcat02 (172.17.0.4): icmp_seq=1 ttl=64 time=0.126 ms 64 bytes from tomcat02 (172.17.0.4): icmp_seq=2 ttl=64 time=0.067 ms root@ls-rK8rbuXz:~ ping: tomcat03: Name or service not known
思考,这个原理是什么呢?我们进入tomcat03中查看下host配置文件
1 2 3 4 5 6 7 8 9 10 11 root@ls-rK8rbuXz:~ 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.17.0.4 tomcat02 83cad5d30841 172.17.0.5 d87cac2a282d
--link
早都过时了,我们不推荐使用! 我们可以使用自定义网络的方式。
自定义网络 内置网络模式分析
基本命令查看
查看所有网络
所有网络模式
网络模式
配置
说明
bridge 模式
–net=bridge 默认值
在Docker网桥docker0上为容器创建新的网络
none模式
–net=none 不配置网络
用户可以稍后进入容器,自行配置
container 模式
–net=container:name/id
容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。
host模式
–net=host
容器和宿主机共享Network namespace
用户自定义
–net=自定义网络
创建容器的时候可以指定为自己定义的网络
查看一个具体的网络的详细信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 root@ls-rK8rbuXz:~ [ { "Name" : "bridge" , "Id" : "cf9cefcfc6ef13ca3dd44adc5e8e6110d9e591aba98633f03bac60be7477f281" , "Created" : "2023-10-09T23:40:27.43579885+08:00" , "Scope" : "local" , "Driver" : "bridge" , "EnableIPv6" : false , "IPAM" : { "Driver" : "default" , "Options" : null, "Config" : [ { "Subnet" : "172.17.0.0/16" , "Gateway" : "172.17.0.1" } ] }, "Internal" : false , "Attachable" : false , "Ingress" : false , "ConfigFrom" : { "Network" : "" }, "ConfigOnly" : false , "Containers" : { "83cad5d308415f1eef98441b0335e2dec47b92e91f02427ee74c56dee8f13bb1" : { "Name" : "tomcat02" , "EndpointID" : "05190a8bd7cef85325fd5f4029f10521ca2e9a8cf90df48b91b199e84775e47e" , "MacAddress" : "02:42:ac:11:00:04" , "IPv4Address" : "172.17.0.4/16" , "IPv6Address" : "" }, "880ef9bc449ee449d87f041e6cdf15d8f9c6db9ef2e5100c8d7b22f169013a34" : { "Name" : "tomcat01" , "EndpointID" : "84761ecb21030854c0f1911e4bc4504aa3439c90e90c4e2351474e4dd7292e75" , "MacAddress" : "02:42:ac:11:00:03" , "IPv4Address" : "172.17.0.3/16" , "IPv6Address" : "" }, "97cb407939ddd7e7293aab51074c758f250f7b3404dbf98168e9395a31793739" : { "Name" : "LAMP" , "EndpointID" : "c0bd47b0292df6f8c56383fc2f83f78e9c00e25f852e8539a6bab29cd38fe67b" , "MacAddress" : "02:42:ac:11:00:02" , "IPv4Address" : "172.17.0.2/16" , "IPv6Address" : "" }, "d87cac2a282dbde98b2fb112d697e6e427611bb1ed87cd275d2ffb2617b34aff" : { "Name" : "tomcat03" , "EndpointID" : "ed4c6920c59d49412acec8ba2a369e81d642dcc725f808dd8437e5a8842beee9" , "MacAddress" : "02:42:ac:11:00:05" , "IPv4Address" : "172.17.0.5/16" , "IPv6Address" : "" } }, "Options" : { "com.docker.network.bridge.default_bridge" : "true" , "com.docker.network.bridge.enable_icc" : "true" , "com.docker.network.bridge.enable_ip_masquerade" : "true" , "com.docker.network.bridge.host_binding_ipv4" : "0.0.0.0" , "com.docker.network.bridge.name" : "docker0" , "com.docker.network.driver.mtu" : "1500" }, "Labels" : {} } ]
自定义网卡 当我们在创建容器的时候,如果没有使用 –net 指定网络模式,则docker会使用默认的 bridge 模式(网卡docker0)。
1 2 3 4 5 6 root@ls-rK8rbuXz:~ 45edbc42a24e2a70a575452e15851d124ad962b1a02816f6fc0ed82a2cab3acb 1. 它是默认的 2. 域名访问不通 3. --link 域名通了,但是删了又不行
我们可以让容器创建的时候,使用我们自定义的网络,接下来我们来创建自定义的网络:
语法:
1 docker network create --driver 网络模式 --subnet 子网地址 --gateway 网关地址 自定义的网络名
1 2 3 4 5 6 7 8 root@ls-rK8rbuXz:~ 26092e185426d8afbc5008968fb01b16bf9055b4572df03dfda33d8cdf21cb69 root@ls-rK8rbuXz:~ NETWORK ID NAME DRIVER SCOPE cf9cefcfc6ef bridge bridge local 85ac0b9f4846 host host local 26092e185426 mynet bridge local 2a42c8845944 none null local
查看创建的网络模式信息
这里我们创建两个容器,tomcat01 和 tomcat02 并使用我们自定义的网络 mynet 观察他们两者之间是否可以相互ping通。
1 2 3 4 5 root@ls-rK8rbuXz:~ c70152d0343779de381f7d54da5b7b296a1141e48a93209995c8a0c840f39091 root@ls-rK8rbuXz:~ root@ls-rK8rbuXz:~ e551d2ee39511125f19e520e30ff8e0c0b5cbfaebf585b99f556fa5f6f7e29bb
经过测试,他们两者之间都可以相互通信,并且支持容器名称访问。
不通网段之间的网络连通
docker0 和自定义网络 mynet 肯定不通,我们使用自定义网络的好处就是网络隔离:
大家公司项目部署的业务都非常多,假设我们有一个商城,我们会有订单业务(操作不同数据),会有 订单业务购物车业务(操作不同缓存)。如果在一个网络下,有的程序猿的恶意代码就不能防止了,所 以我们就在部署的时候网络隔离,创建两个桥接网卡,比如订单业务(里面的数据库,redis,mq,全 部业务 都在order-net网络下)其他业务在其他网络。
那关键的问题来了,如何让 tomcat01 访问 tomcat-net01 或者说是 mynet 网络中的容器? 我们只需要让 tomcat01 连接到 mynet 网络即可。
容器准备:
1 2 3 4 5 6 7 8 9 10 11 root@ls-rK8rbuXz:~ ea45b17c27744b10bf120a1ef3c3dc46700f5871dde1d0f2d12440d7289d3542 root@ls-rK8rbuXz:~ 0e38073fbb1de5a5e6455144c0225e45d6339aa8425ae7ce857d8e81f5d3de5c root@ls-rK8rbuXz:~ 4c75594da8bb227813f03f549a0e8143b937b81b4e5330c2ee036d4c621ec7a4 root@ls-rK8rbuXz:~ 171e8fd959aed00797202ad28fc6c2be8939615c4bef402f34a8485af92e1df7
网络通信准备:
docker network 提供了 connect 命令,用于将一个容器连接到一个网络中。也就是一个容器可以有多个网卡。
将一个容器连接到一个网络中语法:
1 docker network connect <network> <container_name>
命令:
此时,tomcat01容器就连接到了 mynet 网络中:
此时 tomcat01 就有了双IP,可以与 mynet 网络中的容器进行通信。
进入到 tomcat01 容器,发现该容器有了双网卡。
结论: 如果要跨网络操作别人,就需要使用 docker network connect <network> <container_name>
连接。