参考
狂神说
Docker:https://www.bilibili.com/video/BV1og4y1q7M4?p=40
一、Docker概述
1. Docker为什么出现
一款产品的开发往往需要多套环境,比如开发环境、测试环境以及最终的上线环境;环境的配置是时分麻烦的,每一个机器都要部署环境(Redis、ES、Hadoop集群…),尤其是各种集群的部署特别浪费时间,常常会遇到 ”在我电脑上可以运行,在你电脑上不能运行“、”版本更新导致服务不用“、”不能跨平台“ 等等大量问题,这对运维人员来说就十分棘手。
在以前,开发人员发开完成就发布一个jar
或者war
包,其他的都交给运维人员来做;而现在,开发即运维,打包部署上线一套流程走完:开发人员会将项目及其附带的环境一起打包jar+(Redis Jdk ES MySQL)
成一整套发布,称为镜像,这样就不再需要再配置环境,直接执行一整套即可,省去环境配置的麻烦且保证了一致性;
Docker
的出现就是为了解决以上问题,类似于安卓应用:
- java – apk – 发布到应用商店 – 下载即可使用
- java – jar(环境) – 打包项目+环境(镜像) – 发布到Docker仓库 – 下载镜像即可直接运行
Docker 的思想来源于集装箱,打包装箱,每个箱子互相隔离
Docker 通过隔离机制,可以将服务器运行到极致
2. Docker历史
参考:Docker的前生今世
2010 年,几个搞 IT 的年轻人,在美国旧金山成立了一家名叫 dotCloud
的公司。dotCloud 的平台即服务(Platform-as-a-Service, PaaS)提供商。底层技术上,dotCloud 平台利用了 Linux 的 LXC 容器技术。
为了方便创建和管理这些容器,dotCloud 基于 Google 公司推出的 Go 语言开发了一套内部工具,之后被命名为 Docker
。Docker 就是这样诞生的。
如同 Docker 的 Logo 一样,Docker 的思想来源于集装箱。集装箱解决了什么问题?在一艘大船上,可以把货物规整的摆放起来,并且各种各样的货物被集装箱标准化,集装箱与集装箱之间互不影响。那么就不需要专门运送水果的船和专门运送化学用品的船了。只要这些货物封装在不同的集装箱里,就可以用一艘大船把它们都运走。
Docker 技术诞生之后,并没有引起行业的关注。而 dotCloud 公司,作为一家小型创业企业,在激烈的竞争之下,也步履维艰。
正当他们快要坚持不下去的时候,脑子里蹦出了“开源”的想法。什么是“开源”?开源,就是开放源代码。也就是将原来内部保密的程序源代码开放给所有人,然后让大家一起参与进来,贡献代码和意见。
有的软件一开始就是开源的。也有的软件,是混不下去,创造者又不想放弃,所以选择开源。自己养不活,就吃“百家饭”嘛。2013 年 3 月,dotCloud 公司的创始人之一,Docker 之父,28 岁的 「Solomon Hykes」 正式决定,将 Docker 项目开源。
不开则已,一开惊人。越来越多的 IT 工程师发现了 Docker 的优点,然后蜂拥而至,加入 Docker 开源社区。Docker 的人气迅速攀升,速度之快,令人瞠目结舌。
开源当月, Docker 0.1 版本发布。此后的每一个月, Docker 都会发布一个版本。到 2014 年 6 月 9 日, Docker 1.0 版本正式发布。
此时的 Docker,已经成为行业里人气最火爆的开源技术,没有之一。甚至像 Google、微软、Amazon、 VMware 这样的巨头们都对它青睐有加,表示将全力支持。
Docker 火了之后, dotCloud 公司干脆把公司名字也改成了 Docker Inc.
3. 对比虚拟化技术
虚拟机技术
缺点:
- 资源占用十分大
- 冗余步骤多
- 启动慢
容器化技术:不是模拟的一个完整的操作系统
Docker 和 虚拟机技术 的不同:
- 传统虚拟机技术,虚拟出一套硬件,运行一个完整的操作系统,在这个系统上安装和运行软件
- 容器内的应用直接运行在宿主机的内核上,容器没有自己的内核,也没有虚拟硬件,轻便快速,
- 每个容器互相隔离,每个容器都有一个自己的文件系统,互不影响
4. 为什么选择Docker
更高效的利用系统资源
由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。
更快速的启动时间
传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。
一致的运行环境
开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现「这段代码在我机器上没问题啊」 这类问题。
持续交付和部署
对开发和运维(DevOps)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。
使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile 来进行镜像构建,并结合持续集成(Continuous Integration)系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合持续部署(Continuous Delivery/Deployment)系统进行自动部署。
而且使用 Dockerfile 使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的在生产环境中部署该镜像。
更轻松的迁移
由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。
更轻松的维护和扩展
Docker 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker 团队同各个开源项目团队一起维护了一大批高质量的 官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。
引入Docker后:DevOps(开发、运维)
Docker
技术的出现以后,DevOps
的概念由然而生,即开发即运维
应用更快速的交付和部署
-
传统:一堆帮助文档,安装程序
-
Docker:打包镜像发布测试,一键运行
更便捷的升级和扩缩容
- 使用Docker之后,部署应用就和搭积木一样
- 项目打包成一个镜像,比如服务器A出现性能瓶颈,水平拓展,在服务器B上一键运行镜像
更简单的系统运维
- 容器化之后,开发、测试环境高度一致
更高效的计算资源利用
- Docker是内核级别的虚拟化,可以在一个物理机上运行很多容器实例,服务器性能可以被压榨到极致
二、Docker安装配置
1. Docker的基本组成
镜像(image)
镜像就是一个只读的模板,可以通过这个模板创建容器服务,一个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中)
容器(container)
- Docker利用容器技术,独立运行的一个或一组应用。容器是用镜像创建的运行实例。
- 它可以被启用,开始,停止,删除。每个容器都是相互隔离的,保证安全的平台。
- 可以把容器看作是一个简易版的Linux系统(包括root用户权限,进程空间,用户空间和网络空间等)和运行在其中的应用程序。
- 容器的定义和镜像几乎一摸一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是可读可写的
仓库(repository)
-
仓库是集中存放镜像文件的场所。
-
仓库和仓库注册服务器(Registry)是有区别的,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签
-
仓库分为公开仓库(public)和私有仓库(private)两种形式
-
最大的开放仓库是国外的 Docker Hub,存放了数量庞大的镜像供用户下载。
-
国内的公开仓库包括阿里云,网易云都有容器服务器(需要配置镜像加速)等
2. 环境准备
要安装Docker Engine,您需要CentOS 7或8的维护版本。不支持或未测试存档版本。
这里为阿里云 CentOS7
服务器,用 XShell
连接远程服务器工具
# 系统内核
[root@iZ2ze3zdx4jq8v6hetjjuxZ /]# uname -r
3.10.0-1127.13.1.el7.x86_64
# 系统版本
[root@iZ2ze3zdx4jq8v6hetjjuxZ /]# 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"
3. 安装
官网安装教程十分详细,可参照此教程:https://docs.docker.com/engine/install/centos/
1. 卸载旧版本
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
yum报告没有安装这些软件包,即可
2. 安装Docker软件包
sudo yum install -y yum-utils
3. 设置镜像仓库地址
# 默认是国外的
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
# 换成阿里云镜像地址
sudo yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
4. 安装最新版Docker Engine和容器
安装前建议先将将服务器上的软件包信息现在本地缓存,以提高安装软件的速度
sudo yum makecache fast
# docker-ce社区版(docker-ee企业版)
sudo yum install docker-ce docker-ce-cli containerd.io
安装完成后,Docker只安装但并未启动
5. 启动Docker
sudo systemctl start docker
然后可用docker version
命令测试Docker是否安装成功,并查看Docker的版本信息
6. 运行Hello World映像测试
sudo docker run hello-world
我们可用docker images
查看Docker所有的镜像信息
4. 卸载Docker方法
1. 卸载Docker依赖
# 1、卸载Docker依赖: Docker Engine,CLI和Containerd软件包
sudo yum remove docker-ce docker-ce-cli containerd.io
2. 删除Docker资源
# 2、删除Docker资源: 所有镜像,容器和卷(主机上的镜像,容器,卷或自定义配置文件不会自动删除)
sudo rm -rf /var/lib/docker
/var/lib/docker
为Docker的默认工作路径
5. 阿里云镜像加速
登录阿里云账号,找到产品与服务下的弹性计算中的容器镜像服务
点击进入,找到左侧栏 镜像加速器,选择对应的系统,便可看到对用的命令
然后就可配置使用,逐条执行以下命令
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://73z5h6yb.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
到此则配置完毕
三、Docker run的流程和底层原理
1. 流程图
2. 底层原理
Docker是怎么工作的?
- Docker 是一个
Client-Server
结构的系统,Docket 的守护进程运行在主机上,通过Socket从客户端访问 - DockerServer 接收到 DockerClient 的指令,就会执行这个命令
Docker为什么比VM快?
-
Docker有着比虚拟机更少的抽象层,由于Docker不需要Hypervisor实现硬件资源虚拟化,运行在Docker容器上的程序直接使用的都是实际物理机的硬件资源,因此在Cpu、内存利用率上Docker将会在效率上有明显优势。
-
Docker利用的是宿主机的内核,而不需要Guest OS,因此,当新建一个容器时,Docker不需要和虚拟机一样重新加载一个操作系统,避免了引导、加载操作系统内核这个比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载Guest OS,这个新建过程是分钟级别的,而Docker由于直接利用宿主机的操作系统则省略了这个过程,因此新建一个Docker容器只需要几秒钟。
Docker容器 | 虚拟机(VM) | |
---|---|---|
操作系统 | 与宿主机共享OS | 宿主机OS上运行宿主机OS |
存储大小 | 镜像小,便于存储与传输 | 镜像庞大(vmdk等) |
运行性能 | 几乎无额外性能损失 | 操作系统额外的cpu、内存消耗 |
移植性 | 轻便、灵活、适用于Linux | 笨重、与虚拟化技术耦合度高 |
硬件亲和性 | 面向软件开发者 | 面向硬件运维者 |
四、Docker常用命令
帮助文档地址:https://docs.docker.com/reference/
1. 帮助命令
# 显示docker的版本信息
docker version
# 显示docker的系统信息(包括镜像和容器数量)
docker info
# 帮助命令
docker 命令 --help
2. 镜像命令
查看所有镜像
# 查看本地主机所有的镜像
docker images
测试:
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest bf756fb1ae65 12 months ago 13.3kB
# 解释
REPOSITORY 镜像仓库源
TAG 镜像的标签
IMAGE ID 镜像的ID
CREATED 镜像的创建时间
SIZE 镜像大小
#可选项
--all , -a 列出所有镜像
--quiet , -q 只显示镜像ID
搜索镜像
# 搜索镜像
docker search 镜像名
测试:
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker search mysql
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 10414 [OK]
mariadb MariaDB is a community-developed fork of MyS… 3865 [OK]
mysql/mysql-server Optimized MySQL Server Docker images. Create… 762 [OK]
percona Percona Server is a fork of the MySQL relati… 524 [OK]
centos/mysql-57-centos7 MySQL 5.7 SQL database server 87
mysql/mysql-cluster Experimental MySQL Cluster Docker images. Cr… 79
centurylink/mysql Image containing mysql. Optimized to be link… 59 [OK]
bitnami/mysql Bitnami MySQL Docker Image 47 [OK]
deitch/mysql-backup REPLACED! Please use http://hub.docker.com/r… 41 [OK]
databack/mysql-backup Back up mysql databases to... anywhere! 37
prom/mysqld-exporter 37 [OK]
tutum/mysql Base docker image to run a MySQL database se… 35
schickling/mysql-backup-s3 Backup MySQL to S3 (supports periodic backup… 29 [OK]
linuxserver/mysql A Mysql container, brought to you by LinuxSe… 27
circleci/mysql MySQL is a widely used, open-source relation… 20
centos/mysql-56-centos7 MySQL 5.6 SQL database server 20
arey/mysql-client Run a MySQL client from a docker container 17 [OK]
mysql/mysql-router MySQL Router provides transparent routing be… 17
fradelg/mysql-cron-backup MySQL/MariaDB database backup using cron tas… 10 [OK]
yloeffler/mysql-backup This image runs mysqldump to backup data usi… 7 [OK]
openshift/mysql-55-centos7 DEPRECATED: A Centos7 based MySQL v5.5 image… 6
devilbox/mysql Retagged MySQL, MariaDB and PerconaDB offici… 3
ansibleplaybookbundle/mysql-apb An APB which deploys RHSCL MySQL 2 [OK]
jelastic/mysql An image of the MySQL database server mainta… 1
widdpim/mysql-client Dockerized MySQL Client (5.7) including Curl… 1 [OK]
# 可选项
-f, --filter filter 根据提供的条件过滤输出
# 例如搜索STARS大于3000的
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker search mysql -f STARS=3000
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 10414 [OK]
mariadb MariaDB is a community-developed fork of MyS… 3865 [OK]
下载镜像
# 下载镜像
docker pull 镜像名[:tag]
测试:
# 不指定版本号默认下载最新版latest
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker pull mysql
Using default tag: latest
latest: Pulling from library/mysql
a076a628af6f: Pull complete #分层下载,docker image的核心:联合文件系统
f6c208f3f991: Pull complete
88a9455a9165: Pull complete
406c9b8427c6: Pull complete
7c88599c0b25: Pull complete
25b5c6debdaf: Pull complete
43a5816f1617: Pull complete
1a8c919e89bf: Pull complete
9f3cf4bd1a07: Pull complete
80539cea118d: Pull complete
201b3cad54ce: Pull complete
944ba37e1c06: Pull complete
Digest: sha256:feada149cb8ff54eade1336da7c1d080c4a1c7ed82b5e320efb5beebed85ae8c
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest #真实地址
# 指定版本号下载
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker pull mysql:5.7
5.7: Pulling from library/mysql
a076a628af6f: Already exists
f6c208f3f991: Already exists
88a9455a9165: Already exists
406c9b8427c6: Already exists
7c88599c0b25: Already exists
25b5c6debdaf: Already exists
43a5816f1617: Already exists
1831ac1245f4: Pull complete
37677b8c1f79: Pull complete
27e4ac3b0f6e: Pull complete
7227baa8c445: Pull complete
Digest: sha256:b3d1eff023f698cd433695c9506171f0d08a8f92a0c8063c1a4d9db9a55808df
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
下载完再次查看所有镜像,即可看到刚下载的镜像
删除镜像
# 删除镜像
docker rmi
`docker rmi -f 镜像id`:删除指定镜像
`docker rmi -f 镜像id 镜像id 镜像id`:删除指定多个镜像
`docker rmi -f $(docker images -aq)`:删除全部镜像
测试:
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql 5.7 a70d36bc331a 5 days ago 449MB
mysql latest c8562eaf9d81 5 days ago 546MB
hello-world latest bf756fb1ae65 12 months ago 13.3kB
#删除指定镜像
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker rmi -f a70d36bc331a
Untagged: mysql:5.7
Untagged: mysql@sha256:b3d1eff023f698cd433695c9506171f0d08a8f92a0c8063c1a4d9db9a55808df
Deleted: sha256:a70d36bc331a13d297f882d3d63137d24b804f29fa67158c40ad91d5050c39c5
Deleted: sha256:50c77bf7bcddd1f1d97789d80ac2404eec22c860c104e858620d2a2e321f0ef7
Deleted: sha256:14244329b83dfc8982398ee4104a548385652d2bffb957798ff86a419013efd6
Deleted: sha256:6d990477f90af28473eb601a9bca22253f6381e053c5a8edda0a4f027e124a3c
Deleted: sha256:ee0449796df204071589162fc16f8d65586312a40c68d1ba156c93c56f5e5ce8
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql latest c8562eaf9d81 5 days ago 546MB
hello-world latest bf756fb1ae65 12 months ago 13.3kB
#删除所有镜像
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker rmi -f $(docker images -aq)
Untagged: mysql:latest
Untagged: mysql@sha256:feada149cb8ff54eade1336da7c1d080c4a1c7ed82b5e320efb5beebed85ae8c
Deleted: sha256:c8562eaf9d81c779cbfc318d6e01b8e6f86907f1d41233268a2ed83b2f34e748
Deleted: sha256:1b649b85960473808c6b812fc30c3f6a3ff1c0ffdcba5c9435daf01cf7d5373a
Deleted: sha256:19cc889447050c16c797fd209fa114ee219de23facb37c00d4137a4ed4aad922
Deleted: sha256:3c793c06a026d276cf56a6a6a75527026ed9eafa7a7d21a438f7d5ed2314148e
Deleted: sha256:1e1cd89a2bc183a7fea3dab0b543e9924278321ad0921c22cc088adbf3c2e77b
Deleted: sha256:83b2015dfd000588c7c947b2d89b3be7a8e5a3abc6ab562668c358033aa779ec
Deleted: sha256:d08533f1e2acc40ad561a46fc6a76b54c739e6b24f077c183c5709e0a6885312
Deleted: sha256:4f9d91a4728e833d1062fb65a792f06e22e425f63824f260c8b5a64b776ddc38
Deleted: sha256:20bf4c759d1b0d0e6286d2145453af4e0e1b7ba3d4efa3b8bce46817ad4109de
Deleted: sha256:a9371bbdf16ac95cc72555c6ad42f79b9f03a82d964fe89d52bdc5f335a5f42a
Deleted: sha256:5b02130e449d94f51e8ff6e5f7d24802246198749ed9eb064631e63833cd8f1d
Deleted: sha256:ab74465b38bc1acb16c23091df32c5b7033ed55783386cb57acae8efff9f4b37
Deleted: sha256:cb42413394c4059335228c137fe884ff3ab8946a014014309676c25e3ac86864
Untagged: hello-world:latest
Untagged: hello-world@sha256:d58e752213a51785838f9eed2b7a498ffa1cb3aa7f946dda11af39286c3db9a9
Deleted: sha256:bf756fb1ae65adf866bd8c456593cd24beb6a0a061dedf42b26a993176745f6b
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
3. 容器命令
有了镜像才能够创建容器,这里下载一个centos镜像为以下测试做准备
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker pull centos
Using default tag: latest
latest: Pulling from library/centos
7a0437f04f83: Pull complete
Digest: sha256:5528e8b1b1719d34604c87e11dcd1c0a20bedf46e83b5632cdeac91b8c04efc1
Status: Downloaded newer image for centos:latest
docker.io/library/centos:latest
新建容器并启动
# 新建容器并启动
docker run [可选参数] image
# 参数说明
--name="Name" 容器名字,用于区分容器
-d 后台方式运行
-it 使用交互方式运行,进入容器查看内容
-p 指定容器端口(小写)
-p ip:主机端口:容器端口
-p 主机端口:容器端口(最常用)
-P 容器端口
容器端口
-P 随机执行端口(大写)
测试:
#测试,启动进入容器
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker run -it centos /bin/bash
[root@22d0484830c9 /]# ls 查看容器内的centos,基础版本,很多命令不完善
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
#退出容器到主机
[root@22d0484830c9 /]# exit
exit
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# ls
3000 cp cp.tar.gz f.sh hello.c install.sh login.sh read.sh time.sh
列出所有运行的容器
# 列出所有运行的容器
docker ps [可选参数]
# 参数说明
-a 列出当前正在运行以及历史运行过的容器
-n=? 显示最近创建的容器
-q 只显示容器编号
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
22d0484830c9 centos "/bin/bash" About a minute ago Exited (0) About a minute ago condescending_mcnulty
3efe49d28bdd bf756fb1ae65 "/hello" 7 hours ago Exited (0) 7 hours ago confident_babbage
40fc94e7b0a4 bf756fb1ae65 "/hello" 7 months ago Exited (0) 7 months ago inspiring_lovelace
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker ps -n=1
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
22d0484830c9 centos "/bin/bash" 4 minutes ago Exited (0) 3 minutes ago condescending_mcnulty
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker ps -aq
22d0484830c9
3efe49d28bdd
40fc94e7b0a4
退出容器
# 容器停止并退出
exit
# 容器不停止退出
Ctrl+p+q
删除容器
# 删除指定容器,不能删除正在运行的容器,强制删除用rm -f
docker rm 容器id
# 删除所有容器
docker rm -f $(docker ps -aq)
docker ps -a -q|xargs docker rm
测试:
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker ps -aq
6518909c5fb2
3dfd73738e3b
22d0484830c9
3efe49d28bdd
40fc94e7b0a4
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker rm 6518909c5fb2
6518909c5fb2
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker ps -aq
3dfd73738e3b
22d0484830c9
3efe49d28bdd
40fc94e7b0a4
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker rm -f $(docker ps -aq)
3dfd73738e3b
22d0484830c9
3efe49d28bdd
40fc94e7b0a4
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker ps -aq
启动停止容器
docker start 容器id # 启动容器
docker restart 容器id # 重启容器
docker stop 容器id # 停止正在运行的容器
docker kill 容器id # 强制停止当前容器
4. 常用其他命令
后台启动容器
# 后台启动容器
docker run -d 容器名
测试:
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker run -d centos
9606d8980f73ff313c64388f5f82e036072cc7191c3305ab80b371e37d8b1ad7
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9606d8980f73 centos "/bin/bash" 54 seconds ago Exited (0) 53 seconds ago youthful_dubinsky
- 问题:后台启动容器,再用 docker ps 查看发现容器停止
- 原因:docker 容器使用后台运行,就必须有一个前台进程;如果仅仅后台启动,没有应用来提供服务,就会自动停止
查看日志
docker logs [可选参数] 容器ID
--details 显示提供给日志的其他详细信息
-f, --follow 跟踪日志输出
-n, --tail string 指定要显示的日志条数 (默认为全部)
-t, --timestamps 显示时间戳
测试:
# 后台启动容器,同时执行脚本不停打印zsr
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker run -d centos /bin/bash -c "while true;do echo zsr;sleep 1;done"
980daf06de5878e2d3e5c048c7de92817e09e92f20d2d6242ecb15b9b7a5bd02
# 查看运行的容器,此时可以查看到
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
980daf06de58 centos "/bin/bash -c 'while…" 6 seconds ago Up 6 seconds distracted_germain
# 查看日志信息,显示时间戳,指定显示10条日志
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker logs -t -n 10 980daf06de58
2021-01-25T04:53:47.619357189Z zsr
2021-01-25T04:53:48.621476433Z zsr
2021-01-25T04:53:49.623833490Z zsr
2021-01-25T04:53:50.626253957Z zsr
2021-01-25T04:53:51.628526460Z zsr
2021-01-25T04:53:52.630878536Z zsr
2021-01-25T04:53:53.633046201Z zsr
2021-01-25T04:53:54.635296632Z zsr
2021-01-25T04:53:55.637614256Z zsr
2021-01-25T04:53:56.640358130Z zsr
查看容器中的进程
# 查看容器中的进程
docker top 容器ID
测试:
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker top 980daf06de58
UID PID PPID C STIME TTY TIME CMD
root 28359 28339 0 12:52 ? 00:00:00 /bin/bash -c while true;do echo zsr;sleep 1;done
root 29065 28359 0 12:58 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1
查看镜像元数据
# 查看镜像元数据
docker inspect 容器ID
测试:
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker inspect 980daf06de58
[
{
"Id": "980daf06de5878e2d3e5c048c7de92817e09e92f20d2d6242ecb15b9b7a5bd02",
"Created": "2021-01-25T04:52:46.079489883Z",
"Path": "/bin/bash",
"Args": [
"-c",
"while true;do echo zsr;sleep 1;done"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 28359,
"ExitCode": 0,
"Error": "",
"StartedAt": "2021-01-25T04:52:46.469990116Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:300e315adb2f96afe5f0b2780b87f28ae95231fe3bdd1e16b9ba606307728f55",
"ResolvConfPath": "/var/lib/docker/containers/980daf06de5878e2d3e5c048c7de92817e09e92f20d2d6242ecb15b9b7a5bd02/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/980daf06de5878e2d3e5c048c7de92817e09e92f20d2d6242ecb15b9b7a5bd02/hostname",
"HostsPath": "/var/lib/docker/containers/980daf06de5878e2d3e5c048c7de92817e09e92f20d2d6242ecb15b9b7a5bd02/hosts",
"LogPath": "/var/lib/docker/containers/980daf06de5878e2d3e5c048c7de92817e09e92f20d2d6242ecb15b9b7a5bd02/980daf06de5878e2d3e5c048c7de92817e09e92f20d2d6242ecb15b9b7a5bd02-json.log",
"Name": "/distracted_germain",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {
}
},
"NetworkMode": "default",
"PortBindings": {
},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "host",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/c836c661b72e93a97b704d62711facfd82b4f080359405a4382a8dca3f7ce2ed-init/diff:/var/lib/docker/overlay2/e7eaf7928b9265d758185f4ac2e84ab99cb6146cbf37d10a9d9b3ce1ad30ab3e/diff",
"MergedDir": "/var/lib/docker/overlay2/c836c661b72e93a97b704d62711facfd82b4f080359405a4382a8dca3f7ce2ed/merged",
"UpperDir": "/var/lib/docker/overlay2/c836c661b72e93a97b704d62711facfd82b4f080359405a4382a8dca3f7ce2ed/diff",
"WorkDir": "/var/lib/docker/overlay2/c836c661b72e93a97b704d62711facfd82b4f080359405a4382a8dca3f7ce2ed/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "980daf06de58",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/bash",
"-c",
"while true;do echo zsr;sleep 1;done"
],
"Image": "centos",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20201204",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS"
}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "6a7fa868d1b07689ed1307cd6eaffa3d102c13440bddf41b7eedd526a328f03e",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
},
"SandboxKey": "/var/run/docker/netns/6a7fa868d1b0",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "ab462efd8637f15fd7aabe6250429571db2f4dc22e3248278dbe513af5e47e38",
"Gateway": "172.18.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.18.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:12:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "0524bfb4e90c798594ceca6e4099d5b1407f7dcef80435f023f4a1963a35fbb4",
"EndpointID": "ab462efd8637f15fd7aabe6250429571db2f4dc22e3248278dbe513af5e47e38",
"Gateway": "172.18.0.1",
"IPAddress": "172.18.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:12:00:02",
"DriverOpts": null
}
}
}
}
]
进入当前正在运行的容器
容器通常都是使用后台方式运行的,这时候可能需要进入容器,修改一些配置
# 方式一: 进入容器后开启一个新的终端,可在里面进行操作(常用)
docker exec -it 容器id /bin/bash
# 方式二: 进入容器正在执行的终端,不会启动新的进程
docker attach 容器ID
测试:
# 测试方式一
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
980daf06de58 centos "/bin/bash -c 'while…" 2 hours ago Up 2 hours distracted_germain
# 进入到容器
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker exec -it 980daf06de58 /bin/bash
[root@980daf06de58 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
# 测试方式二
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
980daf06de58 centos "/bin/bash -c 'while…" 2 hours ago Up 2 hours distracted_germain
[root@iZ2ze3zdx4jq8v6hetjjuxZ ~]# docker attach 980daf06de58
zsr
zsr
zsr
zsr
zsr
zsr
zsr
#进入死循环...
从容器内拷贝文件到主机
# 从容器内拷贝文件到主机
docker cp 容器id:容器内路径 目的主机路径
测试:
[root@iZ2ze3zdx4jq8v6hetjjuxZ home]# docker run -it centos /bin/bash
[root@64b40f051756 /]# cd /home
[root@64b40f051756 home]# ls
# 在容器内部新建一个文件
[root@64b40f051756 home]# touch 1.txt
[root@64b40f051756 home]# exit
exit
[root@iZ2ze3zdx4jq8v6hetjjuxZ home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@iZ2ze3zdx4jq8v6hetjjuxZ home]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
64b40f051756 centos "/bin/bash" 4 minutes ago Exited (0) 59 seconds ago beautiful_ganguly
c1b3f151ae12 centos "/bin/bash" 7 minutes ago Exited (127) 4 minutes ago nervous_lamarr
60b1f058de74 centos "/bin/bash" 14 minutes ago Exited (0) 12 minutes ago vibrant_jemison
980daf06de58 centos "/bin/bash -c 'while…" 2 hours ago Exited (137) 14 minutes ago distracted_germain
d77c3cdfb7e2 centos "/bin/bash -c 'while…" 3 hours ago Exited (137) 2 hours ago relaxed_meninsky
7706ccced225 centos "/bin/bash -c 'whilr…" 3 hours ago Exited (1) 3 hours ago romantic_hopper
6eebf828ab4c centos "/bin/bash -c 'whilr…" 3 hours ago Exited (1) 3 hours ago brave_goldberg
df422d73861f centos "/bin/bash" 3 hours ago Exited (0) 3 hours ago frosty_panini
744b9b044715 centos "/bin/bash" 3 hours ago Exited (127) 3 hours ago amazing_cori
9606d8980f73 centos "/bin/bash" 3 hours ago Exited (0) 3 hours ago youthful_dubinsky
[root@iZ2ze3zdx4jq8v6hetjjuxZ home]# cd /home
[root@iZ2ze3zdx4jq8v6hetjjuxZ home]# ls
redis www zsr
# 将容器内创建的1.txt拷贝到主机
[root@iZ2ze3zdx4jq8v6hetjjuxZ home]# docker cp 64b40f051756:/home/1.txt /home
[root@iZ2ze3zdx4jq8v6hetjjuxZ home]# ls
1.txt redis www zsr
五、Docker命令实战
1. 部署Nginx
# 1. 搜索镜像
docker search nginx
# 2. 下载镜像
docker pull nginx
# 3. 查看镜像是否下载成功
docker images
# 4. 启动容器(-d:后台运行 --name:容器名 -p:暴露端口 宿主机端口3344:容器端口80)
docker run -d --name nginx01 -p 3344:80 nginx
# 5. 查看容器是否启动
docker ps
# 6. 本机测试
curl localhost:3344
完整代码:
# 1. 搜索镜像
[root@iZ2ze3zdx4jq8v6hetjjuxZ home]# docker search nginx -f STARS=6000
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
nginx Official build of Nginx. 14341 [OK]
# 2. 下载镜像
[root@iZ2ze3zdx4jq8v6hetjjuxZ home]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
a076a628af6f: Pull complete
0732ab25fa22: Pull complete
d7f36f6fe38f: Pull complete
f72584a26f32: Pull complete
7125e4df9063: Pull complete
Digest: sha256:10b8cc432d56da8b61b070f4c7d2543a9ed17c2b23010b43af434fd40e2ca4aa
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
# 3. 查看镜像是否下载成功
[root@iZ2ze3zdx4jq8v6hetjjuxZ home]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest f6d0b4767a6c 12 days ago 133MB
centos latest 300e315adb2f 6 weeks ago 209MB
# 4. 启动容器(-d:后台运行 --name:容器名 -p:暴露端口 宿主机端口3344:容器端口80)
[root@iZ2ze3zdx4jq8v6hetjjuxZ home]# docker run -d --name nginx01 -p 3344:80 nginx
1f9dbdf7f36d69731578314cd861eeed776174ea839100ae2f8987f1bd1b509a
# 5. 查看容器是否启动
[root@iZ2ze3zdx4jq8v6hetjjuxZ home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1f9dbdf7f36d nginx "/docker-entrypoint.…" 8 seconds ago Up 7 seconds 0.0.0.0:3344->80/tcp nginx01
# 6. 本机测试
[root@iZ2ze3zdx4jq8v6hetjjuxZ home]# curl localhost:3344
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# 进入容器
[root@iZ2ze3zdx4jq8v6hetjjuxZ home]# docker exec -it nginx01 /bin/bash
root@1f9dbdf7f36d:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@1f9dbdf7f36d:/# cd /etc/nginx/
root@1f9dbdf7f36d:/etc/nginx# ls
conf.d fastcgi_params koi-utf koi-win mime.types modules nginx.conf scgi_params uwsgi_params win-utf
2. 部署Tomcat
# 官方使用
# 之前我们都是后台启动,停止容器后,仍可以通过docker ps -a命令查到容器的使用记录
# --rm表示用完就删除容器及历史记录,通过命令查不到;
docker run -it --rm tomcat:9.0
# tomcat启动运行
[root@zsr home]# docker run -d -p 3355:8080 --name tomcat01 tomcat
Unable to find image 'tomcat:latest' locally
latest: Pulling from library/tomcat
Digest: sha256:94cc18203335e400dbafcd0633f33c53663b1c1012a13bcad58cced9cd9d1305
Status: Downloaded newer image for tomcat:latest
ffc2e1098b06fc0c0eb259fd93801e97087cbc33d0034a534208a44c491ab7a3
# 进入容器,发现webapps为空
[root@zsr home]# docker exec -it tomcat01 /bin/bash
root@ffc2e1098b06:/usr/local/tomcat# ls
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@ffc2e1098b06:/usr/local/tomcat# cd webapps
root@ffc2e1098b06:/usr/local/tomcat/webapps# ls
3. 部署es+kibana
# es暴露的端口很多
# es十分耗内存
# es的数据一般需要放置在安全目录!挂载
# 启动elasticsearch容器(启动后会很卡顿,因为很占内存)
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
# 监控容器资源消耗(该命令也十分耗资源,服务器卡死)
docker stats [容器ID]
可以看到内存占用率很高;这时候赶紧关闭容器,增加内存的限制,再重新启动一个容器
# 重新启动elasticsearch容器,增加内存限制(-e ES_JAVA_OPTS="-Xms64m -Xmx512m" 最小64m 最大512m),防止服务器卡死
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
# 查看运行的容器
[root@zsr ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b6e7bc8063a5 elasticsearch:7.6.2 "/usr/local/bin/dock…" 39 seconds ago Up 37 seconds 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp elasticsearch01
# 监控容器资源消耗
[root@zsr ~]# docker stats b6e7bc8063a5
可以看到内存占用被限制住,也不再卡了
六、Portainer可视化面板
1. 什么是 portainer ?
Docker 图形化界面管理工具,提供一个后台面板供我们操作
portainer
(先用这个,不是最佳选项;学习CI/CD时再用 Rancher
)
2. 下载
docker run -d -p 8088:9000 \
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
3. 访问测试
我们用docker ps
命令查看一下正在运行的容器,可以看到 portainer 正在运行
[root@zsr ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b72d6033ae2e portainer/portainer "/portainer" 25 seconds ago Up 23 seconds 0.0.0.0:8088->9000/tcp vibrant_dhawan
这时候我们访问外网8088
端口测试一下,这里访问 阿里云服务器公网ip:8088 (注意安全组打开8088端口),就会出现如下界面
然后自己设置一个密码创建用户登录
然后选择 Local
,再点击 Connect
然后就进入了后台管理界面
七、Docker镜像讲解
1. 镜像是什么
镜像 是一种轻量级,可执行的软件包,用来打包软件运行环境和基于运行软件开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
所有的应用,直接打包成docker镜像,就可以直接跑起来
如何获取镜像:
- 从远程仓库下载
- 自己制作一个 Dockerfile
2. Docker镜像加载原理
UnionFS(联合文件系统)
:一种分层、轻量级且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不通目录挂载到同一个虚拟文件系统下(unite serveral directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础,镜像可以通过分层来继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
Docker 的镜像实际上由一层一层的文件系统组成,这种层级的文件系统就是 UnionFS 。
bootfs(boot file system)
主要包含bootloader和kernel,bootloader主要是引导加载kerel,Linux刚启动时会加载 bootfs文件系统,在Docker镜像的最底层时bootfs。这一层与我们典型的Linux/Unix内核是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs
rootfs(root file system)
在bootfs之上,包含的就是典型的 Linux系统中的 /dev、/proc、/bin、/etc 等标准文件。rootfs 就是各种不同的操作系统发行版。
平时安装的虚拟机的CentOS都是好几个G,为什么Docker中才200MB?
对于一个精简的 OS,rootfs 可以很小,只需要包含最基本的命令、工具和程序库就可以了,因为底层使用的是主机的Kernel,自己只需要提供rootfs就可以了。由此可见,对于不同linux发行版,bootfs是基本一致的,rootfs会有差别,因此不同的发行版可以公用bootfs
3. 分层理解
下载示例
当我们下载一个镜像的时候,可以看到,是一层一层的在下载!
为什么Docker镜像要采取这种分层的结构呢?
资源共享:如果有多个镜像从相同的Base镜像构建而来,那么宿主机只需要在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务,且每一层的镜像都可以被共享。
-
查看镜像分层方式可以通过
docker image inspect
命令[root@zsr ~]# docker image inspect mysql:latest [ { "Id": "sha256:c8562eaf9d81c779cbfc318d6e01b8e6f86907f1d41233268a2ed83b2f34e748", "RepoTags": [ "mysql:latest" ], "RepoDigests": [ "mysql@sha256:feada149cb8ff54eade1336da7c1d080c4a1c7ed82b5e320efb5beebed85ae8c" ], "Parent": "", "Comment": "", "Created": "2021-01-18T23:25:55.311110441Z", "Container": "1b772a9e2045f2e123c3ff1d11cc67c9a5fe78b33af9f6a9213aa8cf91f58a6b", "ContainerConfig": { "Hostname": "1b772a9e2045", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "ExposedPorts": { "3306/tcp": { }, "33060/tcp": { } }, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "GOSU_VERSION=1.12", "MYSQL_MAJOR=8.0", "MYSQL_VERSION=8.0.23-1debian10" ], "Cmd": [ "/bin/sh", "-c", "#(nop) ", "CMD [\"mysqld\"]" ], "Image": "sha256:ec58f145c941b51747ba729ab510ff01ca99fa797ec6f4bb8830f6e878e5c66e", "Volumes": { "/var/lib/mysql": { } }, "WorkingDir": "", "Entrypoint": [ "docker-entrypoint.sh" ], "OnBuild": null, "Labels": { } }, "DockerVersion": "19.03.12", "Author": "", "Config": { "Hostname": "", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "ExposedPorts": { "3306/tcp": { }, "33060/tcp": { } }, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "GOSU_VERSION=1.12", "MYSQL_MAJOR=8.0", "MYSQL_VERSION=8.0.23-1debian10" ], "Cmd": [ "mysqld" ], "Image": "sha256:ec58f145c941b51747ba729ab510ff01ca99fa797ec6f4bb8830f6e878e5c66e", "Volumes": { "/var/lib/mysql": { } }, "WorkingDir": "", "Entrypoint": [ "docker-entrypoint.sh" ], "OnBuild": null, "Labels": null }, "Architecture": "amd64", "Os": "linux", "Size": 546118644, "VirtualSize": 546118644, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/468543c2b5fe15aad545f6f06c1a9447f7f12d9c4d846fd2a52cb7e777f95366/diff:/var/lib/docker/overlay2/b9d1aafa99f328fd606f9bc36617d8248d8b66abfe28b61ee29c7f3bb077992f/diff:/var/lib/docker/overlay2/63e10d9d7feec935439a9e001c681fdde27ce10a178b25c486acca518a4fbe4f/diff:/var/lib/docker/overlay2/f6e3f6c93b7d6e5470453603e17b3275677297d7c85edbe1a3ac742454d7a7ff/diff:/var/lib/docker/overlay2/59b36124a39b50c0f2b6c0543a0c4ee1ff6aeaa888f5debaf4ce22c38eaee34f/diff:/var/lib/docker/overlay2/ccff5c078d0a22a57e230f31c1794c6afa643697f9304ba588c301fdbe801ac0/diff:/var/lib/docker/overlay2/98dae5544da3f76f7754d291a7b5532955f06d0f70e7b18d8b962ad8f7800c9e/diff:/var/lib/docker/overlay2/4e76b3dfd15a940cc6c1cd1259f874286c3552eb3bcaa860ead70bbac102b999/diff:/var/lib/docker/overlay2/a95a0edca5d7b3a2b76349964602101194998b4d73b52da526a6067b49240ce3/diff:/var/lib/docker/overlay2/14ebff0838af4ff47eed6e8c712608b48ece23b8262043cd03391819bf2223ae/diff:/var/lib/docker/overlay2/9d91a52dd5189c9f9b4f731398fe1752b3a19155c569222c008dcb58ed214b43/diff", "MergedDir": "/var/lib/docker/overlay2/dc057fc0332771f0a3b2e5f7a94c6bb3624e9a93cd350825c7816a378d312d77/merged", "UpperDir": "/var/lib/docker/overlay2/dc057fc0332771f0a3b2e5f7a94c6bb3624e9a93cd350825c7816a378d312d77/diff", "WorkDir": "/var/lib/docker/overlay2/dc057fc0332771f0a3b2e5f7a94c6bb3624e9a93cd350825c7816a378d312d77/work" }, "Name": "overlay2" }, "RootFS": { "Type": "layers", "Layers": [ "sha256:cb42413394c4059335228c137fe884ff3ab8946a014014309676c25e3ac86864", "sha256:ef4a33cee7a02ffa3c1dd5d2618dcb95e37b899fb7e90d0bb2df32a37396e174", "sha256:74c86dffd46f095d4961730b731a33b19c1abd19f0a7ec1b81ddf09e6d3dfe85", "sha256:6d23902c2a54f36f80946d7225044b2681bac18570af3a58970e325b40ac0d60", "sha256:c484a3b6d84133f3618780f11216facc49f743cefc86e04409f28784a3a0a733", "sha256:0394a41efa739604258181808606eb47798a83383ff52241547583939ffb297c", "sha256:98d98806c8acefda16226c37045e3733a751c3cb165fde1182cbc324cde06f78", "sha256:d35a1217c926c4d5fc2e8a9f914e565d46a1da65f461e5cb9f09f7b34953bb97", "sha256:9577a2d5d759695f1b0e92efd95e7e46b1ac4c4c75350bac0045c94bd308732a", "sha256:d60ed0726e3751a08f8d1d1696f51bb3ac47276b2c4f271272f167f532b4285a", "sha256:ab82e085fd825c64ed10839fcae191d2169657b9585438676d1f54fb626162be", "sha256:c080af299e3f1cab9e0bbe183259aa64014e6c560fea1c0534ffe95b0180b2a3" ] }, "Metadata": { "LastTagTime": "0001-01-01T00:00:00Z" } } ]
其中
Layers
就表示了每一层
理解
-
所有的 Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上创建新的镜像层
-
举一个简单的例子,假如基于 Ubuntu Linux 16.04 创建一个新的镜像,这就是新镜像的第一层;如果要在该镜像中添加python包,就会在基础镜像层之上创建了新的一个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合。下图中举了一个简单的例子,每个镜像层包含 3 个文件,而镜像包含了来自两个镜像层的 6 个文件
上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有 6 个文件,这是因为最上层中的文件7 是文件 5 的一个更新版本
这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。
Docker 通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。
Linux 上可用的存储引擎有 AUFS、Overlay2、Device Mapper、Btrfs 以及 ZFS。顾名思义,每种存储引擎都基于 Linux 中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。
Docker 在 Windows 上仅支持 windowsfilter 一种存储引擎,该引擎基于 NTFS 文件系统之上实现了分层和 CoW[1]。
下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。
特点
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!
这一层就是我们通常说的容器层,容器之下的都叫镜像层!
4. Commit镜像
当我们通过镜像启动一个容器时,分为了两层:容器层和镜像层;镜像层是可读的,容器层可写,我们的所有操作都是基于容器层,当我们对容器层修改完后,就可以再将修改后的容器层和不变的镜像曾一起打包成一个新的镜像,也就是本节要讲的
Commit
镜像
# 提交容器成为一个新的副本
docker commit
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[TAG]
实战测试:
# 启动一个默认的Tomcat
[root@zsr ~]# docker run -it -p 8088:8080 tomcat /bin/bash
root@2594ca9eefcb:/usr/local/tomcat# cd webapps
root@2594ca9eefcb:/usr/local/tomcat/webapps# ls
root@2594ca9eefcb:/usr/local/tomcat/webapps# cd ..
# 发现这个默认的Tomcat没有webapps应用(官方镜像默认没有)
root@2594ca9eefcb:/usr/local/tomcat# cd webapps
root@2594ca9eefcb:/usr/local/tomcat/webapps# ls
# 从webapps.dist拷贝到webapps中,使其有基本文件
root@2594ca9eefcb:/usr/local/tomcat/webapps# cd ..
root@2594ca9eefcb:/usr/local/tomcat# ls
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@2594ca9eefcb:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@2594ca9eefcb:/usr/local/tomcat# cd webapps
root@2594ca9eefcb:/usr/local/tomcat/webapps# ls
ROOT docs examples host-manager manager
# 提交修改后的容器
[root@zsr ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7c548ecd440f tomcat "/bin/bash" 39 seconds ago Up 38 seconds 0.0.0.0:8088->8080/tcp brave_hertz
[root@zsr ~]# docker commit -a "zsr" -m="copy files from webapps.dist to webapps" 7c548ecd440f tomcat_zsr:1.0
sha256:3be2283d4c0d49f733f33f849c5ae95415ba7dfb71672112c0f36391c694ef8b
[root@zsr ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat_zsr 1.0 3be2283d4c0d 37 seconds ago 653MB
mysql latest c8562eaf9d81 9 days ago 546MB
tomcat 9.0 040bdb29ab37 2 weeks ago 649MB
tomcat latest 040bdb29ab37 2 weeks ago 649MB
nginx latest f6d0b4767a6c 2 weeks ago 133MB
centos latest 300e315adb2f 7 weeks ago 209MB
portainer/portainer latest 62771b0b9b09 6 months ago 79.1MB
elasticsearch 7.6.2 f29a1ee41030 10 months ago 791MB
八、容器数据卷
1. 什么是容器数据卷
docker的理念:将应用和环境打包成一个镜像!通过镜像启动容器运行
- 问题:在容器中存储的程序数据是需要持久化的,不能容器删了数据也随之删除。比如,安装一个MySQL容器,在其中存储了大量数据,结果把容器删了数据也没了,就相当于删库跑路,这是不可能发生的
数据卷技术的引入:我们希望Docker容器产生的数据可以自动同步到本地,这样容器删了数据并不会丢失;同时数据也可在容器之间共享。这就是卷技术,也就是目录的挂载,将容器内的目录挂载到linux上
总结:容器的持久化和同步操作!容器间也可以实现数据共享!
2. 使用数据卷
docker run -it -v 主机目录:容器内目录
测试:
[root@zsr ~]# docker run -it -v /home/test:/home centos /bin/bash
启动之后可以用docker inspect
查看容器详细信息,可以看到挂载的信息
我们开两个窗口分别进入相对应挂载的目录,在容器内/home目录下新建一个文件,在主机/home/test目录下同步出现该文件
同样,如果我们关闭退出停止容器,在主机内的/home/test路径下新建文件2.txt,在容器内/home下也会同步,我们再次打开容器可以看到2.txt
实战:安装MySQL
# 1. 下载mysql:5.7镜像
[root@zsr test]# docker pull mysql:5.7
5.7: Pulling from library/mysql
a076a628af6f: Already exists
f6c208f3f991: Already exists
88a9455a9165: Already exists
406c9b8427c6: Already exists
7c88599c0b25: Already exists
25b5c6debdaf: Already exists
43a5816f1617: Already exists
1831ac1245f4: Pull complete
37677b8c1f79: Pull complete
27e4ac3b0f6e: Pull complete
7227baa8c445: Pull complete
Digest: sha256:b3d1eff023f698cd433695c9506171f0d08a8f92a0c8063c1a4d9db9a55808df
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
# 2. 启动mysql容器
-d 后台运行
-p 端口映射
-v 卷挂载
-e 环境配置
--name 容器名字
[root@zsr test]# docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
67271dad5e807c42dccfa4803c2743d59e7bf75937bb8adc0df504e151965385
启动之后,我们本机连接一下试试,记得打开阿里云服务器安全组设置的3310端口
点击连接,连接成功,则说明docker部署成功
我们回到xshell,查看主机下的`/home/mysql`目录,可以看到`conf`和`data`两个目录,我们进入`data`目录,可以看到相关文件
如果我们在navicat中新建一个数据库
再回到xhell,查看data目录,可以看到新增了test
,即进行了同步
如果我们删除容器,数据仍在不会丢失,仍保留在本地
3. 具名和匿名挂载
匿名挂载
# 匿名挂载: -v:容器内路径(没有写容器外路径)
docker run -d -P --name nginx01 -v /etc/nginx nginx
# 查看所有volume的情况
docker volume ls
具名挂载(常用)
# 具名挂载: -v 卷名:容器内路径
docker run -d -P --name nginx02 -v specific-nginx:/etc/nginx nginx
# 查看所有volume的情况
docker volume ls
# 查specific-nginx卷的具体信息
docker volume inspect specific-nginx
所有docker容器内的卷,没有指定目录情况下都是在/var/lib/docker/volumes/卷名/_data
下
拓展
# 通过 容器内路径:ro/rw 限制读写权限
ro:read only 只读,该路径文件只能通过宿主机来操作,容器内无法操作
rw:read write 可读可写
docker run -d -P --name nginx02 -v specific-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v specific-nginx:/etc/nginx:rw nginx
4. 初识Dockerfile
Dockerfile
就是用来构建 docker 镜像的构建文件,就是一段命令脚本,通过这个脚本可以生成一个镜像
通过这个脚本可以生成镜像,镜像是一层一层的,脚本中就是一个个命令,每个命令对应一层
# 创建一个dockerfile文件
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "----end----"
CMD /bin/bash
完整:
[root@zsr home]# ls
1.txt mysql redis test www zsr
[root@zsr home]# mkdir docker-test-volume
[root@zsr home]# ls
1.txt docker-test-volume mysql redis test www zsr
[root@zsr home]# cd docker-test-volume/
[root@zsr docker-test-volume]# clear
[root@zsr docker-test-volume]# pwd
/home/docker-test-volume
[root@zsr docker-test-volume]# vim dockerfile1
[root@zsr docker-test-volume]# cat dockerfile1
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "----end----"
CMD /bin/bash
[root@zsr docker-test-volume]# docker build -f ./dockerfile1 -t zsr/centos:1.0 .
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos
---> 300e315adb2f
Step 2/4 : VOLUME ["volume01","volume02"]
---> Running in 50aca2e71aa4
Removing intermediate container 50aca2e71aa4
---> fab18ace6a3a
Step 3/4 : CMD echo "----end----"
---> Running in 6de412d0d33e
Removing intermediate container 6de412d0d33e
---> dd29a1e732b7
Step 4/4 : CMD /bin/bash
---> Running in bb9c9b146eea
Removing intermediate container bb9c9b146eea
---> 52d008bba0ac
Successfully built 52d008bba0ac
Successfully tagged zsr/centos:1.0
然后就可以查到自己构建的镜像
我们来通过自己创建的镜像启动容器,查看其中的内容,可以看到生成镜像时自动挂载的数据卷目录volume01
和volume02
这两个数据卷一定与外部有一个同步的目录!且我们设置的是匿名挂载
通过以下命令查看具体的外部挂载路径
docker inspect b7cf8107f9fb
5. 数据卷容器
实现多个容器之间同步数据
启动3个容器,通过我们自己创建的镜像启动
docker run -it --name docker01 zsr/centos:1.0
docker run -it --name docker02 --volumes-from docker01 zsr/centos:1.0
docker run -it --name docker03 --volumes-from docker01 zsr/centos:1.0
我们可以删除docker01
,但数据并不会丢失;只要有一个容器再用,就不会丢失,因为数据卷是采用双向拷贝的技术,即使删除了一个容器,但数据已经拷贝到了其他容器中
总结:
- 容器之间配置信息的传递,数据卷容器的声明周期一直持续到没有容器使用为止
- 如果数据同步到了本地,本地的数据是不会删除的
九、DockerFile
1. DockerFile介绍
dockerfile
是用来构建docker镜像的文件
构建步骤:
- 编写一个dockerfile文件
- docker build 构建成一个镜像
- docker run 运行镜像
- docker push 发布镜像(DockerHub、阿里云镜像仓库)
dockerHub:https://hub.docker.com/
这里以搜索centos
镜像为例
我们点击官方的镜像源,会跳转到一个github
地址,里面就是dockerfile
FROM scratch
ADD centos-8-x86_64.tar.xz /
LABEL org.label-schema.schema-version="1.0" org.label-schema.name="CentOS Base Image" org.label-schema.vendor="CentOS" org.label-schema.license="GPLv2" org.label-schema.build-date="20201204"
CMD ["/bin/bash"]
可以看到功能很少,官方的镜像都是基础包,我们通常要搭建自己的镜像
2. DockerFile的构建过程
基础知识:
- 每个保留关键字(指令)都必须是大写字母
- 执行顺序从上往下顺序执行
#
代表注释- 每条指令都会创建并提交一个新的镜像层
DockerFile
是面向开发的,逐渐成为企业交付的标准,以后发布项目就是打包成一个镜像,就需要编写dockerfile文件,十分简单!
3. DockerFile指令
常见指令
FROM # 基础镜像,从此开始构建
MAINTAINER # 镜像作者,通常为姓名+邮箱
RUN # 镜像构建时需要执行的命令
ADD # 在镜像中需要添加的文件(比如基础镜像centos中要添加tomcat)
WORKDIR # 镜像的工作目录
VOLUME # 容器数据卷,挂载主机的目录
EXPOSE # 对外的暴露端口
CMD # 指定容器启动时要运行的命令(只有最后一个生效,可被替代)
ENTRYPOINT # 指定容器启动时要运行的命令(可以追加命令)
ONBUILD # 当构建一个被继承DockerFile时就会运行ONBUILD指令
COPY # 类似ADD,将文件拷贝到镜像中
ENV # 构建时的环境变量
FROM | 基础镜像,从此开始构建 |
---|---|
MAINTAINER | 镜像作者,通常为姓名+邮箱 |
RUN | 镜像构建时需要执行的命令 |
ADD | 在镜像中需要添加的文件(比如基础镜像centos中要添加tomcat) |
WORKDIR | 镜像的工作目录 |
VOLUME | 容器数据卷,挂载主机的目录 |
EXPOSE | 对外的暴露端口 |
CMD | 指定容器启动时要运行的命令(只有最后一个生效,可被替代) |
ENTRYPOINT | 指定容器启动时要运行的命令(可以追加命令) |
ONBUILD | 当构建一个被继承DockerFile时就会运行ONBUILD指令 |
COPY | 类似ADD,将文件拷贝到镜像中 |
ENV | 构建时的环境变量 |
CMD和ENTRYPOINT的区别
测试CMD:
# 编写的dockerfile文件
[root@zsr dockerfile]# cat test-CMD-dockerfile
FROM centos
CMD ["ls","-a"]
# 构建镜像
[root@zsr dockerfile]# docker build -f test-CMD-dockerfile -t cmdtest .
Sending build context to Docker daemon 3.072kB
Step 1/2 : FROM centos
---> 300e315adb2f
Step 2/2 : CMD ["ls","-a"]
---> Running in 36cf3cc47759
Removing intermediate container 36cf3cc47759
---> da35633333da
Successfully built da35633333da
Successfully tagged cmdtest:latest
# 通过镜像启动容器,看到 ls -a 命令生效
[root@zsr dockerfile]# docker run da35633333da
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
# 启动容器时追加 -l 命令,发现报错,这是因为CMD会覆盖以前的命令
[root@zsr dockerfile]# docker run da35633333da -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:370: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
# 启动容器时追加 ls -al 命令,不报错,这是因为CMD会覆盖以前的命令
[root@zsr dockerfile]# docker run da35633333da ls -al
total 56
drwxr-xr-x 1 root root 4096 Jan 30 10:58 .
drwxr-xr-x 1 root root 4096 Jan 30 10:58 ..
-rwxr-xr-x 1 root root 0 Jan 30 10:58 .dockerenv
lrwxrwxrwx 1 root root 7 Nov 3 15:22 bin -> usr/bin
drwxr-xr-x 5 root root 340 Jan 30 10:58 dev
drwxr-xr-x 1 root root 4096 Jan 30 10:58 etc
drwxr-xr-x 2 root root 4096 Nov 3 15:22 home
lrwxrwxrwx 1 root root 7 Nov 3 15:22 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Nov 3 15:22 lib64 -> usr/lib64
drwx------ 2 root root 4096 Dec 4 17:37 lost+found
drwxr-xr-x 2 root root 4096 Nov 3 15:22 media
drwxr-xr-x 2 root root 4096 Nov 3 15:22 mnt
drwxr-xr-x 2 root root 4096 Nov 3 15:22 opt
dr-xr-xr-x 119 root root 0 Jan 30 10:58 proc
dr-xr-x--- 2 root root 4096 Dec 4 17:37 root
drwxr-xr-x 11 root root 4096 Dec 4 17:37 run
lrwxrwxrwx 1 root root 8 Nov 3 15:22 sbin -> usr/sbin
drwxr-xr-x 2 root root 4096 Nov 3 15:22 srv
dr-xr-xr-x 13 root root 0 Jan 28 13:30 sys
drwxrwxrwt 7 root root 4096 Dec 4 17:37 tmp
drwxr-xr-x 12 root root 4096 Dec 4 17:37 usr
drwxr-xr-x 20 root root 4096 Dec 4 17:37 var
测试ENTRYPOINT:
# 编写的dockerfile文件
FROM centos
ENTRYPOINT ["ls","-a"]
# 构建镜像
[root@zsr dockerfile]# docker build -f test-ENTRYPOINT-dockerfile -t entrypoint-test .
Sending build context to Docker daemon 4.096kB
Step 1/2 : FROM centos
---> 300e315adb2f
Step 2/2 : ENTRYPOINT ["ls","-a"]
---> Running in 74c8223d1e35
Removing intermediate container 74c8223d1e35
---> 27f4e359bf92
Successfully built 27f4e359bf92
Successfully tagged entrypoint-test:latest
# 通过镜像启动容器,看到 ls -a 命令生效
[root@zsr dockerfile]# docker run 27f4e359bf92
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
# 启动容器时追加 -l 命令,成功,这是因为ENTRYPOINT会追加到以前的命令
[root@zsr dockerfile]# docker run 27f4e359bf92 -l
total 56
drwxr-xr-x 1 root root 4096 Jan 30 11:03 .
drwxr-xr-x 1 root root 4096 Jan 30 11:03 ..
-rwxr-xr-x 1 root root 0 Jan 30 11:03 .dockerenv
lrwxrwxrwx 1 root root 7 Nov 3 15:22 bin -> usr/bin
drwxr-xr-x 5 root root 340 Jan 30 11:03 dev
drwxr-xr-x 1 root root 4096 Jan 30 11:03 etc
drwxr-xr-x 2 root root 4096 Nov 3 15:22 home
lrwxrwxrwx 1 root root 7 Nov 3 15:22 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Nov 3 15:22 lib64 -> usr/lib64
drwx------ 2 root root 4096 Dec 4 17:37 lost+found
drwxr-xr-x 2 root root 4096 Nov 3 15:22 media
drwxr-xr-x 2 root root 4096 Nov 3 15:22 mnt
drwxr-xr-x 2 root root 4096 Nov 3 15:22 opt
dr-xr-xr-x 119 root root 0 Jan 30 11:03 proc
dr-xr-x--- 2 root root 4096 Dec 4 17:37 root
drwxr-xr-x 11 root root 4096 Dec 4 17:37 run
lrwxrwxrwx 1 root root 8 Nov 3 15:22 sbin -> usr/sbin
drwxr-xr-x 2 root root 4096 Nov 3 15:22 srv
dr-xr-xr-x 13 root root 0 Jan 28 13:30 sys
drwxrwxrwt 7 root root 4096 Dec 4 17:37 tmp
drwxr-xr-x 12 root root 4096 Dec 4 17:37 usr
drwxr-xr-x 20 root root 4096 Dec 4 17:37 var
4. 实战:构建自己的CentOS
官网centos
dockerfile
:Docker Hub 大多数基础镜像都是scratch
,然后添加所需的配置进行构建FROM scratch ADD centos-8-x86_64.tar.xz / LABEL org.label-schema.schema-version="1.0" org.label-schema.name="CentOS Base Image" org.label-schema.vendor="CentOS" org.label-schema.license="GPLv2" org.label-schema.build-date="20201204" CMD ["/bin/bash"]
1. 编写dockerfile
基于官网的centos
构建自己的centos
,编写一个centos-dockerfile
# 编写自己的centos-dockerfile
[root@zsr dockerfile]# vim centos-dockerfile
[root@zsr dockerfile]# cat centos-dockerfile
FROM centos
MAINTAINER zsr<1412578784@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 8088
CMD echo $MYPATH
CMD echo "----end----"
CMD /bin/bash
2. 通过dockerfile构建镜像
# 通过centos-dockerfile构建镜像
# 命令: docker build -f dockerfile路径 -t 镜像名:[tag] .
[root@zsr dockerfile]# docker build -f centos-dockerfile -t mycentos:0.1 .
Sending build context to Docker daemon 2.048kB
Step 1/10 : FROM centos
---> 300e315adb2f
Step 2/10 : MAINTAINER zsr<1412578784@qq.com>
---> Running in 07cb579c0233
Removing intermediate container 07cb579c0233
---> 47a448db7079
Step 3/10 : ENV MYPATH /usr/local
---> Running in fb3d1ac73261
Removing intermediate container fb3d1ac73261
---> 74e47975e555
Step 4/10 : WORKDIR $MYPATH
---> Running in c596e71a7e68
Removing intermediate container c596e71a7e68
---> 9588d6a7b4b9
Step 5/10 : RUN yum -y install vim
---> Running in f005ef7c0b02
CentOS Linux 8 - AppStream 3.4 MB/s | 6.3 MB 00:01
CentOS Linux 8 - BaseOS 1.4 MB/s | 2.3 MB 00:01
CentOS Linux 8 - Extras 15 kB/s | 8.6 kB 00:00
Dependencies resolved.
================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
vim-enhanced x86_64 2:8.0.1763-15.el8 appstream 1.4 M
Installing dependencies:
gpm-libs x86_64 1.20.7-15.el8 appstream 39 k
vim-common x86_64 2:8.0.1763-15.el8 appstream 6.3 M
vim-filesystem noarch 2:8.0.1763-15.el8 appstream 48 k
which x86_64 2.21-12.el8 baseos 49 k
Transaction Summary
================================================================================
Install 5 Packages
Total download size: 7.8 M
Installed size: 30 M
Downloading Packages:
(1/5): gpm-libs-1.20.7-15.el8.x86_64.rpm 316 kB/s | 39 kB 00:00
(2/5): vim-filesystem-8.0.1763-15.el8.noarch.rp 1.2 MB/s | 48 kB 00:00
(3/5): which-2.21-12.el8.x86_64.rpm 1.6 MB/s | 49 kB 00:00
(4/5): vim-enhanced-8.0.1763-15.el8.x86_64.rpm 4.8 MB/s | 1.4 MB 00:00
(5/5): vim-common-8.0.1763-15.el8.x86_64.rpm 20 MB/s | 6.3 MB 00:00
--------------------------------------------------------------------------------
Total 3.5 MB/s | 7.8 MB 00:02
warning: /var/cache/dnf/appstream-02e86d1c976ab532/packages/gpm-libs-1.20.7-15.el8.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 8483c65d: NOKEY
CentOS Linux 8 - AppStream 983 kB/s | 1.6 kB 00:00
Importing GPG key 0x8483C65D:
Userid : "CentOS (CentOS Official Signing Key) <security@centos.org>"
Fingerprint: 99DB 70FA E1D7 CE22 7FB6 4882 05B5 55B3 8483 C65D
From : /etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
Key imported successfully
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : which-2.21-12.el8.x86_64 1/5
Installing : vim-filesystem-2:8.0.1763-15.el8.noarch 2/5
Installing : vim-common-2:8.0.1763-15.el8.x86_64 3/5
Installing : gpm-libs-1.20.7-15.el8.x86_64 4/5
Running scriptlet: gpm-libs-1.20.7-15.el8.x86_64 4/5
Installing : vim-enhanced-2:8.0.1763-15.el8.x86_64 5/5
Running scriptlet: vim-enhanced-2:8.0.1763-15.el8.x86_64 5/5
Running scriptlet: vim-common-2:8.0.1763-15.el8.x86_64 5/5
Verifying : gpm-libs-1.20.7-15.el8.x86_64 1/5
Verifying : vim-common-2:8.0.1763-15.el8.x86_64 2/5
Verifying : vim-enhanced-2:8.0.1763-15.el8.x86_64 3/5
Verifying : vim-filesystem-2:8.0.1763-15.el8.noarch 4/5
Verifying : which-2.21-12.el8.x86_64 5/5
Installed:
gpm-libs-1.20.7-15.el8.x86_64 vim-common-2:8.0.1763-15.el8.x86_64
vim-enhanced-2:8.0.1763-15.el8.x86_64 vim-filesystem-2:8.0.1763-15.el8.noarch
which-2.21-12.el8.x86_64
Complete!
Removing intermediate container f005ef7c0b02
---> 0c3951bc6949
Step 6/10 : RUN yum -y install net-tools
---> Running in 4646de41c5d7
Last metadata expiration check: 0:00:11 ago on Sat Jan 30 04:10:15 2021.
Dependencies resolved.
================================================================================
Package Architecture Version Repository Size
================================================================================
Installing:
net-tools x86_64 2.0-0.52.20160912git.el8 baseos 322 k
Transaction Summary
================================================================================
Install 1 Package
Total download size: 322 k
Installed size: 942 k
Downloading Packages:
net-tools-2.0-0.52.20160912git.el8.x86_64.rpm 4.4 MB/s | 322 kB 00:00
--------------------------------------------------------------------------------
Total 692 kB/s | 322 kB 00:00
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : net-tools-2.0-0.52.20160912git.el8.x86_64 1/1
Running scriptlet: net-tools-2.0-0.52.20160912git.el8.x86_64 1/1
Verifying : net-tools-2.0-0.52.20160912git.el8.x86_64 1/1
Installed:
net-tools-2.0-0.52.20160912git.el8.x86_64
Complete!
Removing intermediate container 4646de41c5d7
---> 72be4892b90e
Step 7/10 : EXPOSE 8088
---> Running in 57afa2232032
Removing intermediate container 57afa2232032
---> afadc63b8b9b
Step 8/10 : CMD echo $MYPATH
---> Running in 29d0dd8ea502
Removing intermediate container 29d0dd8ea502
---> 909e565c58a0
Step 9/10 : CMD echo "----end----"
---> Running in 04c2f5807be3
Removing intermediate container 04c2f5807be3
---> d4dcc5359a4d
Step 10/10 : CMD /bin/bash
---> Running in 10a0d1c49ad2
Removing intermediate container 10a0d1c49ad2
---> 1c97191097fc
Successfully built 1c97191097fc
Successfully tagged mycentos:0.1
然后用docker images
命令就可以查看到构建的镜像mycentos
同样,我们可以用docker history
命令查看镜像的构建过程
3. 通过镜像启动容器
[root@zsr dockerfile]# docker run -it mycentos:0.1
[root@a5f99e5c1589 local]# pwd
/usr/local
[root@a5f99e5c1589 local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.18.0.5 netmask 255.255.0.0 broadcast 172.18.255.255
ether 02:42:ac:12:00:05 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@a5f99e5c1589 local]# vim 1.txt
对比之前官方的centos
,新增了ifconfig
、vim
等命令
5. 实战:构建自己的Tomcat
1. 准备镜像文件
准备
Tomcat
压缩包,而Tomcat
运行需要依赖于jdk
,所以还需要jdk
的压缩包
tomcat下载地址:https://tomcat.apache.org/download-90.cgi
jdk下载地址:https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html
然后将两个压缩包通过xftp
拷贝到服务器的/home/tomcat
目录下
可在服务器中查看
2. 编写dockerfile文件
编写
dockerfile
文件,官方命名为Dockerfile
,这样就不需要通过-f
指定,build时会自动寻找这个文件
FROM centos
MAINTAINER zsr<1412578784@qq.com>
COPY readme.txt /usr/local/readme.txt
ADD jdk-8u281-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.41.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk
ENV CALSSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.41
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.41
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.41/bin/startup.sh && tail -F /url/local/apache-tomcat-9.0.41/bin/logs/catalina.out
3. 构建镜像
[root@zsr tomcat]# docker build -t mytomcat .
Sending build context to Docker daemon 155.2MB
Step 1/15 : FROM centos
---> 300e315adb2f
Step 2/15 : MAINTAINER zsr<1412578784@qq.com>
---> Using cache
---> 47a448db7079
Step 3/15 : COPY readme.txt /usr/local/readme.txt
---> 8dd0d2ce8867
Step 4/15 : ADD jdk-8u281-linux-x64.tar.gz /usr/local/
---> 7c5ab3a8ed6e
Step 5/15 : ADD apache-tomcat-9.0.41.tar.gz /usr/local/
---> e2f1d80dde55
Step 6/15 : RUN yum -y install vim
---> Running in 75ad35b83d68
CentOS Linux 8 - AppStream 4.2 MB/s | 6.3 MB 00:01
CentOS Linux 8 - BaseOS 633 kB/s | 2.3 MB 00:03
CentOS Linux 8 - Extras 14 kB/s | 8.6 kB 00:00
Dependencies resolved.
================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
vim-enhanced x86_64 2:8.0.1763-15.el8 appstream 1.4 M
Installing dependencies:
gpm-libs x86_64 1.20.7-15.el8 appstream 39 k
vim-common x86_64 2:8.0.1763-15.el8 appstream 6.3 M
vim-filesystem noarch 2:8.0.1763-15.el8 appstream 48 k
which x86_64 2.21-12.el8 baseos 49 k
Transaction Summary
================================================================================
Install 5 Packages
Total download size: 7.8 M
Installed size: 30 M
Downloading Packages:
(1/5): gpm-libs-1.20.7-15.el8.x86_64.rpm 495 kB/s | 39 kB 00:00
(2/5): vim-filesystem-8.0.1763-15.el8.noarch.rp 1.5 MB/s | 48 kB 00:00
(3/5): which-2.21-12.el8.x86_64.rpm 201 kB/s | 49 kB 00:00
(4/5): vim-enhanced-8.0.1763-15.el8.x86_64.rpm 2.3 MB/s | 1.4 MB 00:00
(5/5): vim-common-8.0.1763-15.el8.x86_64.rpm 2.9 MB/s | 6.3 MB 00:02
--------------------------------------------------------------------------------
Total 792 kB/s | 7.8 MB 00:10
warning: /var/cache/dnf/appstream-02e86d1c976ab532/packages/gpm-libs-1.20.7-15.el8.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 8483c65d: NOKEY
CentOS Linux 8 - AppStream 1.0 MB/s | 1.6 kB 00:00
Importing GPG key 0x8483C65D:
Userid : "CentOS (CentOS Official Signing Key) <security@centos.org>"
Fingerprint: 99DB 70FA E1D7 CE22 7FB6 4882 05B5 55B3 8483 C65D
From : /etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
Key imported successfully
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : which-2.21-12.el8.x86_64 1/5
Installing : vim-filesystem-2:8.0.1763-15.el8.noarch 2/5
Installing : vim-common-2:8.0.1763-15.el8.x86_64 3/5
Installing : gpm-libs-1.20.7-15.el8.x86_64 4/5
Running scriptlet: gpm-libs-1.20.7-15.el8.x86_64 4/5
Installing : vim-enhanced-2:8.0.1763-15.el8.x86_64 5/5
Running scriptlet: vim-enhanced-2:8.0.1763-15.el8.x86_64 5/5
Running scriptlet: vim-common-2:8.0.1763-15.el8.x86_64 5/5
Verifying : gpm-libs-1.20.7-15.el8.x86_64 1/5
Verifying : vim-common-2:8.0.1763-15.el8.x86_64 2/5
Verifying : vim-enhanced-2:8.0.1763-15.el8.x86_64 3/5
Verifying : vim-filesystem-2:8.0.1763-15.el8.noarch 4/5
Verifying : which-2.21-12.el8.x86_64 5/5
Installed:
gpm-libs-1.20.7-15.el8.x86_64 vim-common-2:8.0.1763-15.el8.x86_64
vim-enhanced-2:8.0.1763-15.el8.x86_64 vim-filesystem-2:8.0.1763-15.el8.noarch
which-2.21-12.el8.x86_64
Complete!
Removing intermediate container 75ad35b83d68
---> 223e446850cd
Step 7/15 : ENV MYPATH /usr/local
---> Running in 75bb312ba150
Removing intermediate container 75bb312ba150
---> 0365605d3b03
Step 8/15 : WORKDIR $MYPATH
---> Running in 3a21e6991d81
Removing intermediate container 3a21e6991d81
---> 29130451ac38
Step 9/15 : ENV JAVA_HOME /usr/local/jdk
---> Running in 1ecd36c1d9f7
Removing intermediate container 1ecd36c1d9f7
---> fe6bf481c29a
Step 10/15 : ENV CALSSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
---> Running in 02236cc9eea3
Removing intermediate container 02236cc9eea3
---> c30c9a3c9b7a
Step 11/15 : ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.41
---> Running in b6e97820a257
Removing intermediate container b6e97820a257
---> adc11a0fcc4b
Step 12/15 : ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.41
---> Running in b92bfa0ad8ab
Removing intermediate container b92bfa0ad8ab
---> 9604504f196d
Step 13/15 : ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
---> Running in 025388f720e6
Removing intermediate container 025388f720e6
---> 486df4c3100f
Step 14/15 : EXPOSE 8080
---> Running in 46a3f73f7a63
Removing intermediate container 46a3f73f7a63
---> 3decd97962e6
Step 15/15 : CMD /usr/local/apache-tomcat-9.0.41/bin/startup.sh && tail -F /url/local/apache-tomcat-9.0.41/bin/logs/catalina.out
---> Running in b0c9afffc1f1
Removing intermediate container b0c9afffc1f1
---> 42338715d10f
Successfully built 42338715d10f
Successfully tagged mytomcat:latest
4. 启动容器
[root@zsr tomcat]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat latest 42338715d10f About a minute ago 640MB
entrypoint-test latest 27f4e359bf92 4 hours ago 209MB
cmdtest latest da35633333da 4 hours ago 209MB
mycentos 0.1 1c97191097fc 11 hours ago 291MB
zsr/centos 1.0 52d008bba0ac 2 days ago 209MB
tomcat_zsr 1.0 3be2283d4c0d 2 days ago 653MB
mysql 5.7 a70d36bc331a 11 days ago 449MB
mysql latest c8562eaf9d81 11 days ago 546MB
tomcat 9.0 040bdb29ab37 2 weeks ago 649MB
tomcat latest 040bdb29ab37 2 weeks ago 649MB
nginx latest f6d0b4767a6c 2 weeks ago 133MB
centos latest 300e315adb2f 7 weeks ago 209MB
portainer/portainer latest 62771b0b9b09 6 months ago 79.1MB
elasticsearch 7.6.2 f29a1ee41030 10 months ago 791MB
[root@zsr tomcat]# docker run -d -P 47.95.238.165:8088:8080 --name zsrtomcat -v /home/tomcat/test:/usr/local/apache-tomcat-9.0.41/webapps/test -v /home/tomcat/logs:/usr/local/apache-tomcat-9.0.41/logs mytomcat
04d4ec8d3986250927c3d2174ac11130e3b29b943b18fd908e434cf7545d4aab
[root@zsr tomcat]# ls
apache-tomcat-9.0.41.tar.gz Dockerfile jdk-8u281-linux-x64.tar.gz logs readme.txt test
5. 进入容器
[root@zsr tomcat]# docker exec -it 04d4ec8d3986 /bin/bash
[root@04d4ec8d3986 local]# pwd
/usr/local
[root@04d4ec8d3986 local]# ls -l
total 52
drwxr-xr-x 1 root root 4096 Jan 30 14:58 apache-tomcat-9.0.41
drwxr-xr-x 2 root root 4096 Nov 3 15:22 bin
drwxr-xr-x 2 root root 4096 Nov 3 15:22 etc
drwxr-xr-x 2 root root 4096 Nov 3 15:22 games
drwxr-xr-x 2 root root 4096 Nov 3 15:22 include
drwxr-xr-x 8 10143 10143 4096 Dec 9 12:50 jdk1.8.0_281
drwxr-xr-x 2 root root 4096 Nov 3 15:22 lib
drwxr-xr-x 3 root root 4096 Dec 4 17:37 lib64
drwxr-xr-x 2 root root 4096 Nov 3 15:22 libexec
-rw-r--r-- 1 root root 0 Jan 30 12:18 readme.txt
drwxr-xr-x 2 root root 4096 Nov 3 15:22 sbin
drwxr-xr-x 5 root root 4096 Dec 4 17:37 share
drwxr-xr-x 2 root root 4096 Nov 3 15:22 src
[root@04d4ec8d3986 local]# cd apache-tomcat-9.0.41/
[root@04d4ec8d3986 apache-tomcat-9.0.41]# ls -l
total 148
-rw-r----- 1 root root 18982 Dec 3 11:48 BUILDING.txt
-rw-r----- 1 root root 5409 Dec 3 11:48 CONTRIBUTING.md
-rw-r----- 1 root root 57092 Dec 3 11:48 LICENSE
-rw-r----- 1 root root 2333 Dec 3 11:48 NOTICE
-rw-r----- 1 root root 3257 Dec 3 11:48 README.md
-rw-r----- 1 root root 6898 Dec 3 11:48 RELEASE-NOTES
-rw-r----- 1 root root 16507 Dec 3 11:48 RUNNING.txt
drwxr-x--- 2 root root 4096 Dec 3 11:48 bin
drwx------ 2 root root 4096 Dec 3 11:48 conf
drwxr-x--- 2 root root 4096 Dec 3 11:45 lib
drwxr-xr-x 2 root root 4096 Jan 30 15:06 logs
drwxr-x--- 2 root root 4096 Dec 3 11:45 temp
drwxr-x--- 1 root root 4096 Jan 30 15:06 webapps
drwxr-x--- 2 root root 4096 Dec 3 11:43 work
6. 访问测试
同样,用公网IP:8088
可以访问到
7. 发布项目
我们已经做了卷挂载,本机的/home/tomcat/test
挂载到容器的/usr/local/apache-tomcat-9.0.41/webapps/test
目录,因此我们只需要在本机对应目录项发布项目就会自动同步到容器中
我们在/home/tomcat/test
目录下新建WEB-INF
目录,在其中创建web.xml
文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
</web-app>
然后在test
目录下创建一个index.jsp
页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>zsr</title>
</head>
<body>
Hello World!<br/>
<%
out.println("mytomcat测试");
%>
</body>
</html>
然后浏览器输入localhost:8088/test
即可看到页面
6. 发布镜像到 Docker Hub
首先要有自己
Docker Hub
的账号
1. 登录 Docker Hub
docker login
命令用于登录
[root@zsr test]# docker login --help
Usage: docker login [OPTIONS] [SERVER]
Log in to a Docker 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
2. 提交到 Docker Hub
用docker tag
命令重命名要发布到镜像,名称格式为:账户名/镜像名:版本号
[root@zsr test]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat latest 42338715d10f 6 days ago 640MB
[root@zsr test]# docker tag 42338715d10f bareth/tomcat:1.0
[root@zsr test]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
bareth/tomcat 1.0 42338715d10f 6 days ago 640MB
mytomcat latest 42338715d10f 6 days ago 640MB
然后push即可
[root@zsr ~]# docker push bareth/tomcat:1.0
The push refers to repository [docker.io/bareth/tomcat]
95a2375d854b: Pushing 15.68MB/58.05MB
028764aa589d: Pushing 5.345MB/15.83MB
aea92a4c5330: Pushing 4.422MB/356.6MB
ea60ecf88e36: Pushed
2653d992f4ef: Pushing 10.95MB/209.3MB
7. 发布镜像到阿里云镜像
1. 创建阿里云镜像仓库
首先登录阿里云,找到 容器镜像服务
点击进入,然后 创建一个镜像仓库
仓库类型选择 本地仓库
便成功创建了仓库
我们点击进入刚创建的仓库可以查看相关信息
2. 提交到阿里云镜像仓库
1、登录阿里云Docker Registry
docker login --username=bareth registry.cn-beijing.aliyuncs.com
- 登录的用户名为阿里云账号全名,密码为开通服务时设置的密码
2、使用docker tag
命令重命名要发布的镜像
[root@zsr test]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat latest 42338715d10f 6 days ago 640MB
[root@zsr test]# docker tag 42338715d10f registry.cn-beijing.aliyuncs.com/bareth/docker-test:1.0
[root@zsr ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat latest 42338715d10f 2 weeks ago 640MB
registry.cn-beijing.aliyuncs.com/bareth/docker-test 1.0 42338715d10f 2 weeks ago 640MB
3、push到阿里云镜像仓库
[root@zsr ~]# docker push registry.cn-beijing.aliyuncs.com/bareth/docker-test:1.0
The push refers to repository [docker.io/bareth/tomcat]
小结
十、Docker网络
1. Docker网络原理
当我们用ip addr
命令查看服务器内部网络地址时,可以发现三个地址:
- 127.0.0.1 本机回环地址
- 172.17.223.207 服务器内网IP地址
- 172.18.0.1 docker0地址
这里的docker0
地址就是安装docker时,采用 桥接模式 使用 evth-pair 技术分配的地址
==docker是如何处理容器网络访问的?==比如有一个tomcat容器,一个mysql容器;tomcat中运行着一个web项目,这个项目需要访问mysql。这是如何实现的呢?
我们首先启动一个tomcat容器
# 启动一个容器
[root@zsr ~]# docker run -d -P --name tomcat01 tomcat
Unable to find image 'tomcat:latest' locally
latest: Pulling from library/tomcat
b9a857cbf04d: Pull complete
d557ee20540b: Pull complete
3b9ca4f00c2e: Pull complete
667fd949ed93: Pull complete
661d3b55f657: Pull complete
511ef4338a0b: Pull complete
a56db448fefe: Pull complete
00612a99c7dc: Pull complete
326f9601c512: Pull complete
c547db74f1e1: Pull complete
Digest: sha256:94cc18203335e400dbafcd0633f33c53663b1c1012a13bcad58cced9cd9d1305
Status: Downloaded newer image for tomcat:latest
c3b8a6a222bfcd73d5cf350d330b3a1c536d0eb5a0676eb24e193664659f2fcd
然后我们查看容器内部网络地址,可以发现 eth0@if89 这个ip地址127.0.0.1
,这是docker分配的
# 查看容器内部网络地址,可以发现 eth0@if89 这个ip地址,这是docker分配的
[root@zsr ~]# docker exec -it tomcat01 ip addr
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
88: eth0@if89: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0
valid_lft forever preferred_lft forever
我们ping该容器内地址,发现可以ping通,因为127.0.0.2
和docker0地址127.0.0.1
网络前缀相同,是处于统一网段的,所以可以ping通
# ping容器内地址,发现可以ping通docker容器内部
[root@zsr ~]# ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.100 ms
64 bytes from 172.18.0.2: icmp_seq=2 ttl=64 time=0.071 ms
64 bytes from 172.18.0.2: icmp_seq=3 ttl=64 time=0.070 ms
原理:
- 每启动一个docker容器时,docker就会给该容器分配一个ip地址
我们再次在服务器上使用ip addr
测试,可以发现多了一对网络地址,这就是启动tomcat容器docker为其分配的地址
如果我们再启动一个tomcat容器,可以看到又多了一对网络地址
我们发现每次新增的网络地址都是一对一对的88/89 90/91
,这就是evth-pair
技术,就是一对虚拟设备接口,成对出现,一段连着协议,一段彼此相连;容器内的88连接了主机的89,容器内的90连接了主机的91;
evth-pair
充当了一个桥梁,实现了主机可以ping通容器内部ip地址,用于连接各种虚拟网络设备
那么 tomcar01
和tomcat02
这两个容器能否ping通呢?当然是可以的,因为两个容器内的ip地址都桥接了主机相应的ip地址,都与docker0
地址处于同一网段,因此可以ping通
# tomcat02 ping tomcat01可以ping通
[root@zsr ~]# docker exec -it tomcat02 ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.127 ms
64 bytes from 172.18.0.2: icmp_seq=2 ttl=64 time=0.109 ms
64 bytes from 172.18.0.2: icmp_seq=3 ttl=64 time=0.100 ms
可用docker netowork
命令查看该网桥中的所有配置
[root@zsr ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
81fa37acd3b5 bridge bridge local
d1c3276f2d1f host host local
40b12350fa4a none null local
[root@zsr ~]# docker network inspect 81fa37acd3b5
[
{
"Name": "bridge",
"Id": "81fa37acd3b5fe63542a50cb6dda629a7434fa9fdebccedb7e8c24e859a31b76",
"Created": "2021-02-06T20:58:24.660018691+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"1cc06da893c10d4ef1bdf7e590860b44cf55a0c506b57b64dda44551ef06d816": {
"Name": "tomcat03",
"EndpointID": "1c3a39f04598dc4b966f51b54e82c15a77c522e49fbfe618d70668332abc9ba3",
"MacAddress": "02:42:ac:12:00:04",
"IPv4Address": "172.18.0.4/16",
"IPv6Address": ""
},
"c3b8a6a222bfcd73d5cf350d330b3a1c536d0eb5a0676eb24e193664659f2fcd": {
"Name": "tomcat01",
"EndpointID": "1b5015b0de628870b5498984aae24c0175dd8cb2663de9c9c6f6bce0694771e0",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
},
"ff19965390f0f4231130227b252290ea759d407ecbb2b0c0dcc11261d5687f26": {
"Name": "tomcat02",
"EndpointID": "8ae0342e9e42fe3b9a19c70f1646500ae7dae519781719b7b8097eb9b43b5811",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/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": {
}
}
]
结论:容器和容器之间是可以互相ping通的
所有的容器不指定网络的情况下,都是通过 docker0
路由的,docker会给容器分配一个默认的可用ip
- Docker 使用的是Linux的桥接,宿主机中是一个Docker容器的网桥docker0
- Docker 中所有的网络接口都是虚拟的,转发效率高,只要容器删除,对应的网桥就删除
2. 容器互联–link
如果我们编写了一个微服务,连接数据库的ip地址变化了,此时数据连接就会断开,服务不可用;如果此时能够通过容器名字连接数据库,就可以解决数据库连接的问题;
如果tomcat01
直接通过pingtomcat02
的容器名,会报错
[root@zsr ~]# docker exec -it tomcat01 ping tomcat02
ping: tomcat02: Name or service not known
那么如何解决这个问题呢?可以在创建容器时用--link
指定连接的容器,此时就可以通过容器名来ping通了
[root@zsr ~]# docker run -d -P --name tomcat03 --link tomcat01 tomcat
1cc06da893c10d4ef1bdf7e590860b44cf55a0c506b57b64dda44551ef06d816
[root@zsr ~]# docker exec -it tomcat03 ping tomcat01
PING tomcat01 (172.18.0.2) 56(84) bytes of data.
64 bytes from tomcat01 (172.18.0.2): icmp_seq=1 ttl=64 time=0.127 ms
64 bytes from tomcat01 (172.18.0.2): icmp_seq=2 ttl=64 time=0.103 ms
64 bytes from tomcat01 (172.18.0.2): icmp_seq=3 ttl=64 time=0.103 ms
但是反过来ping则无法ping通
[root@zsr ~]# docker exec -it tomcat01 ping tomcat03
ping: tomcat03: Name or service not known
原理:通过--link
使tomcat03
在本地hosts中配置了 tomcat02
的ip与容器名的映射
3. 自定义网络
# 查看所有的网络
[root@zsr ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
81fa37acd3b5 bridge bridge local
d1c3276f2d1f host host local
40b12350fa4a none null local
网络模式
bridge
:桥接(默认)none
:不配置网络host
:主机模式,和宿主机共享网络container
:容器网络联通(使用少!)
测试:
当我们启动一个容器时,其实有默认参数--net bridge
,这也就是docker0
,是默认的方式,上述提到可以用--link
进行互联实现通过容器名访问,但是比较繁琐,不建议使用;
# 启动一个容器时带默认参数 --net bridge
docker run -d -P --name mytomcat tomcat
docker run -d -P --name mytomcat --net bridge tomcat
建议自定义一个网络,所有的服务都在自定义的网络中进行使用!
# 创建一个网络mynet,采用默认的桥接模式,子网地址192.168.0.0,网关192.168.0.1
[root@zsr ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
2e6be259e1f43f884fbf9e24aa3cc1b238b91bd1e9be3ba0abcfbefd3e106450
[root@zsr ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
81fa37acd3b5 bridge bridge local
d1c3276f2d1f host host local
2e6be259e1f4 mynet bridge local
40b12350fa4a none null local
可查看自定义网络的详细信息
我们指定使用自定义网络mynet
来启动两个容器
[root@zsr ~]# docker run -d -P --name mynet-tomcat01 --net mynet tomcat
2795bf15cd21ec608c02840bd7488942da4838d47662b0b204e663003fa49a3b
[root@zsr ~]# docker run -d -P --name mynet-tomcat02 --net mynet tomcat
41b416dbf35eb55164ffe024d120a17db60aa0a501f20ef3ce40d3c180a67517
然后再查看mynet
的详细信息,可以看到这两个容器以及分配的IP地址
再次测试ping连接,发现自定义的网络解决了docker0
的缺点,可以直接通过容器名来访问
[root@zsr ~]# docker exec -it mynet-tomcat01 ping mynet-tomcat02
PING mynet-tomcat02 (192.168.0.3) 56(84) bytes of data.
64 bytes from mynet-tomcat02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.094 ms
64 bytes from mynet-tomcat02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.094 ms
64 bytes from mynet-tomcat02.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.158 ms
^C
--- mynet-tomcat02 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 3ms
rtt min/avg/max/mdev = 0.094/0.115/0.158/0.031 ms
应用场景:
不同的集群(redis,mysql)用不同的网络,使用自己的子网,保证集群的安全及健康
4. 网络联通
上述我们启动了四个容器,分别是默认docker0
网络下的tomcat01/tomcat02
,自定义网络mynet
网络下的mynet-tomcat01/mynet-tomcat02
我们画个图来理解一下
此时可以实现tomcat01
到mynet-tomcat01
的互联吗?答案当然是否定的,因为是处于不同的网段,我们可以进行测试
[root@zsr ~]# docker exec -it 192.18.0.2 ping 172.18.0.2
Error: No such container: 192.18.0.2
那么怎么实现tomcat01
到mynet-tomcat01
的互联呢?可以使用docker network connect
命令
# 测试联通tomcat01到mynet-tomcat01
[root@zsr ~]# docker network connect mynet tomcat01
然后查看mynet
得详细信息,可以发现联通之后就是将tomcat01
的放入mynet
网络中,也就实现了一个容器两个ip,类似于阿里云的公网IP和私网IP,都是可以访问
联通后我们再次ping连接测试,成功ping通!
[root@zsr ~]# docker exec -it tomcat01 ping mynet-tomcat01
PING mynet-tomcat01 (192.168.0.2) 56(84) bytes of data.
64 bytes from mynet-tomcat01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.091 ms
64 bytes from mynet-tomcat01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.100 ms
^C
--- mynet-tomcat01 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1ms
rtt min/avg/max/mdev = 0.091/0.095/0.100/0.010 ms
实战:部署Redis集群
# 自定义一个网络
[root@zsr ~]# docker network create redis --subnet 172.38.0.0/16
92f7a807fc739e3eb7b6e56df5a1c6bc3e701e0a61a544f04e7a2e549538ad20
# 通过脚本创建6个redis配置
for port in $(seq 1 6); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
# 通过脚本启动6个容器
for i in `seq 1 6`; \
do \
docker run -d -p 637${i}:6379 -p 1637${i}:16379 --name redis-${i} \
-v /mydata/redis/node-${i}/data:/data \
-v /mydata/redis/node-${i}/conf/redis.conf:/etc/redis/redis.conf \
--net redis --ip 172.38.0.1${i} redis:6.0 redis-server /etc/redis/redis.conf
done
# 进入redis-1容器
[root@zsr /]# docker exec -it redis-1 /bin/sh
# pwd
/data
# ls
appendonly.aof nodes.conf
# 配置集群
# redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.38.0.15:6379 to 172.38.0.11:6379
Adding replica 172.38.0.16:6379 to 172.38.0.12:6379
Adding replica 172.38.0.14:6379 to 172.38.0.13:6379
M: f693f5b7cc515154a532aa5f48ff627d2827e205 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
M: b233e1c2053a77c2351b511e784579cd50a3e5a8 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
M: da06f6994fe142969f313fa7c6d8cb94cd1facb7 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
S: 944f7e0f2e3082745c2e999470f969d53cd1bdd9 172.38.0.14:6379
replicates da06f6994fe142969f313fa7c6d8cb94cd1facb7
S: eaab096391c79d4d3d42be66fcc66cb2d724720b 172.38.0.15:6379
replicates f693f5b7cc515154a532aa5f48ff627d2827e205
S: 09ba78c0f4f1848a6a9c6d0b9ccc42a159a394a4 172.38.0.16:6379
replicates b233e1c2053a77c2351b511e784579cd50a3e5a8
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
.
>>> Performing Cluster Check (using node 172.38.0.11:6379)
M: f693f5b7cc515154a532aa5f48ff627d2827e205 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 944f7e0f2e3082745c2e999470f969d53cd1bdd9 172.38.0.14:6379
slots: (0 slots) slave
replicates da06f6994fe142969f313fa7c6d8cb94cd1facb7
M: da06f6994fe142969f313fa7c6d8cb94cd1facb7 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: eaab096391c79d4d3d42be66fcc66cb2d724720b 172.38.0.15:6379
slots: (0 slots) slave
replicates f693f5b7cc515154a532aa5f48ff627d2827e205
S: 09ba78c0f4f1848a6a9c6d0b9ccc42a159a394a4 172.38.0.16:6379
slots: (0 slots) slave
replicates b233e1c2053a77c2351b511e784579cd50a3e5a8
M: b233e1c2053a77c2351b511e784579cd50a3e5a8 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
# 连接集群查看信息
# redis-cli -c
127.0.0.1:6379> cluster info # 查看集群信息
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:461
cluster_stats_messages_pong_sent:454
cluster_stats_messages_sent:915
cluster_stats_messages_ping_received:449
cluster_stats_messages_pong_received:461
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:915
127.0.0.1:6379> cluster nodes # 查看集群节点信息,三主三从
f693f5b7cc515154a532aa5f48ff627d2827e205 172.38.0.11:6379@16379 myself,master - 0 1613876713000 1 connected 0-5460
944f7e0f2e3082745c2e999470f969d53cd1bdd9 172.38.0.14:6379@16379 slave da06f6994fe142969f313fa7c6d8cb94cd1facb7 0 1613876713071 3 connected
da06f6994fe142969f313fa7c6d8cb94cd1facb7 172.38.0.13:6379@16379 master - 0 1613876714675 3 connected 10923-16383
eaab096391c79d4d3d42be66fcc66cb2d724720b 172.38.0.15:6379@16379 slave f693f5b7cc515154a532aa5f48ff627d2827e205 0 1613876713000 1 connected
09ba78c0f4f1848a6a9c6d0b9ccc42a159a394a4 172.38.0.16:6379@16379 slave b233e1c2053a77c2351b511e784579cd50a3e5a8 0 1613876715175 2 connected
b233e1c2053a77c2351b511e784579cd50a3e5a8 172.38.0.12:6379@16379 master - 0 1613876713673 2 connected 5461-10922
此时我们添加一个键值对,可以看到是由172.38.0.13
也就是redis-3
主机来处理的服务
也就是a
的值存在redis-3
主机中,那对应的从机应该也有a
的值,也就是说如果redis-3
服务挂掉,可以从对应的从机中取出a
的值
# 停止redis-3容器
[root@zsr ~]# docker stop redis-3
redis-3
然后再重新获取a
的值,可以看到是从redis-4
中取得值,也就是redis-3
的从机,实现了高可用,主机挂掉从机自动替代主机
再查看节点的详细信息,可以看到redis-3
主机挂掉,redis-4
成为新的主机
十一、SpringBoot微服务&docker
1. 构建springboot项目
首先新建一个springboot
项目
然后编写一个controller
,在主程序目录下新建controller
包,其中新建HelloController.java
package com.zsr.docker_test.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello() {
return "hello";
}
}
然后启动主程序进行测试,访问localhost:8080/hello
,出现如下页面即成功
2. 打包应用
点击package
进行打包
打包成功后,可以看到生成的target
目录中打包生成的.jar
文件
我们用命令行测试一下该jar
包能否运行,在其目录下打开cmd,输入以下命令
jaava -jar docker_test-0.0.1-SNAPSHOT.jar
成功启动代表打包成功
3. 编写Dockerfile
在项目根目录下新建Dockerfile
FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
4. 构建镜像
将编写好的Dockerfile
和打包生成的docker_test-0.0.1-SNAPSHOT.jar
文件上传到服务器
然后用命令构建镜像
[root@zsr IDEA]# ls
Dockerfile docker_test-0.0.1-SNAPSHOT.jar
[root@zsr IDEA]# docker build -t first-project .
Sending build context to Docker daemon 16.55MB
Step 1/5 : FROM java:8
8: Pulling from library/java
5040bd298390: Pull complete
fce5728aad85: Pull complete
76610ec20bf5: Pull complete
60170fec2151: Pull complete
e98f73de8f0d: Pull complete
11f7af24ed9c: Pull complete
49e2d6393f32: Pull complete
bb9cdec9c7f3: Pull complete
Digest: sha256:c1ff613e8ba25833d2e1940da0940c3824f03f802c449f3d1815a66b7f8c0e9d
Status: Downloaded newer image for java:8
---> d23bdf5b1b1b
Step 2/5 : COPY *.jar /app.jar
---> 63fda5bdcb6d
Step 3/5 : CMD ["--server.port=8080"]
---> Running in 5e94d333492d
Removing intermediate container 5e94d333492d
---> 59bd2f4e0120
Step 4/5 : EXPOSE 8080
---> Running in 99c4427313de
Removing intermediate container 99c4427313de
---> d4792bf4f884
Step 5/5 : ENTRYPOINT ["java","-jar","/app.jar"]
---> Running in da3be5f92a55
Removing intermediate container da3be5f92a55
---> 2df101d6382c
Successfully built 2df101d6382c
Successfully tagged first-project:latest
然后便可看到刚生成的镜像
5. 启动容器测试
[root@zsr IDEA]# docker run -d -P --name springboot-project first-project
33bbe58ea88c99f0cdc40cda78f04b81c21d48d0dab59c2e9e2896a8899f5cc8
[root@zsr IDEA]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
33bbe58ea88c first-project "java -jar /app.jar …" 4 seconds ago Up 3 seconds 0.0.0.0:49163->8080/tcp springboot-project
[root@zsr IDEA]# curl localhost:49163/hello
hello[root@zsr IDEA]#
根据测试结果,成功启动项目,访问的/hello
请求返回结果正确
6. 发布镜像
将镜像发布至Docker Hub
或者阿里云镜像仓库,然后别人使用直接pull下来即可运行
转载:https://blog.csdn.net/qq_45173404/article/details/114266009