Docker 快速入门
1. Docker历史
2010年,几个的年轻人,就在美国的旧金山成立了一家公司 dotcloud。做一些Paas平台的创业公司!从事LXC(Linux Container容器)有关的容器技术!Linux Container容器是一种内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源。他们将自己的技术(容器化技术)命名就是 Docker。Docker刚刚延生的时候,没有引起行业的注意!虽然获得了创业孵化器(Y Combinator)的支持、也获得过一些融资,但随着IT巨头们(微软、谷歌、亚马逊等厂商)也进入PaaS凭他,dotCloud举步维艰,眼看就活不下去!
2013年,dotCloud的创始人,28岁的Solomon Hykes做了一个艰难的决定,将dotCloud的核心引擎开源,这项核心引擎技术能够将Linux容器中的应用程序、代码打包,轻松的在服务器之间进行迁移。这个基于LXC技术的核心管理引擎开源后,让全世界的技术人员感到惊艳。感叹这一切太方便了!!越来越多的人发现docker的优点!火了。Docker每个月都会更新一个版本!2014年6月9日,Docker1.0发布!1.0版本的发布,标志着docker平台已经足够成熟稳定,并可以被应用到生产环境。
docker为什么这么火?因为docker十分的轻巧!在容器技术出来之前,我们都是使用虚拟机技术!在window中装一个VMware,通过这个软件我们可以虚拟出来一台或者多台电脑!笨重!虚拟机也属于虚拟化技术,Docker容器技术,也是一种虚拟化技术!
2. Docker版本
docker 从 17.03 版本之后分为 CE(Community Edition: 社区版) 和 EE(Enterprise Edition: 企业版),本教程使用社区版(CE)。
3. DevOps(开发,运维)
-
开发环境Windows,最后发布到Linux!
传统:开发jar,运维来做!
现在:开发打包部署上线,一套流程做完!
-
应用更快速的交付和部署
传统:帮助文档,安装程序。
Docker:打包镜像发布测试一键运行。
-
更便捷的升级和扩缩容
使用了 Docker之后,我们部署应用就和搭积木一样
项目打包为一个镜像,扩展服务器A!服务器B
-
更简单的系统运维
在容器化之后,我们的开发,测试环境都是高度一致的
更高效的计算资源利用
Docker是内核级别的虚拟化,可以在一个物理机上可以运行很多的容器实例!服务器的性能可以被压榨到极致
4. 什么是Docker
当人们说“Docker”时,他们通常是指 Docker Engine,它是一个客户端 - 服务器应用程序,由 Docker守护进程、一个REST API指定与守护进程交互的接口、和一个命令行接口(CLI)与守护进程通信(通过封装REST API)。Docker Engine 从 CLI 中接受docker 命令,例如 docker run 、docker ps 来列出正在运行的容器、docker images 来列出镜像,等等。
-
docker是一个软件,可以运行在window、linux、mac等各种操作系统上。
-
docker 是一个开源的应用容器引擎,基于Go 语言开发并遵从 Apache2.0 协议开源,项目代码托管在github上进行维护
-
docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上。
-
容器是完全使用沙箱机制,相互之间不会有任何接口,更重要的是容器性能开销极低。
5. Docker基本组成
docker主机(Host):安装了Docker程序的机器(Docker直接安装在操作系统之上);
docker仓库(Registry):用来保存各种打包好的软件镜像;仓库分为公有仓库和私有仓库。(很类似maven)
docker镜像(Images):软件打包好的镜像;放在docker仓库中;
docker容器(Container):镜像启动后的实例称为一个容器;容器是独立运行的一个或一组应用
6. Docker与操作系统
docker是一种轻量级的虚拟化方式。与传统操作系统技术的特性比较如下表:
传统的虚拟机方式提供的是相对封闭的隔离。Docker利用Linux系统上的多种防护技术实现了严格的隔离可靠性,并且可以整合众多安全工具。从 1.3.0版本开始,docker重点改善了容器的安全控制和镜像的安全机制, 极大提高了使用docker的安全性
7. Docker安装
当我们安装 Docker 的时候,会涉及两个主要组件:
-
Docker CLI:客户端
-
Docker daemon:有时也被称为“服务端”或者“引擎”
硬件安装要求:
由于我用Ubuntu ,这里示范Ubuntu 安装过程:
# step 1: 安装必要的一些系统工具
sudo apt-get update
sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common
# step 2: 安装GPG证书
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
# Step 3: 写入软件源信息
sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
# Step 4: 更新并安装 Docker-CE
sudo apt-get -y update
sudo apt-get -y install docker-ce
# 安装指定版本的Docker-CE:
# Step 1: 查找Docker-CE的版本:
# apt-cache madison docker-ce
# docker-ce | 17.03.1~ce-0~ubuntu-xenial | http://mirrors.aliyun.com/docker-ce/linux/ubuntu xenial/stable amd64 Packages
# docker-ce | 17.03.0~ce-0~ubuntu-xenial | http://mirrors.aliyun.com/docker-ce/linux/ubuntu xenial/stable amd64 Packages
# Step 2: 安装指定版本的Docker-CE: (VERSION 例如上面的 17.03.1~ce-0~ubuntu-xenial)
# sudo apt-get -y install docker-ce=[VERSION]
安装成功查看版本:
docker -v
docker version
docker info
8. Docker命令分类
-
Docker环境信息 — docker [info|version]
-
容器生命周期管理 — docker [create|exec|run|start|stop|restart|kill|rm|pause|unpause]
-
容器操作管理 — docker [ps|inspect|top|attach|wait|export|port|rename|stat]
-
容器rootfs命令 — docker [commit|cp|diff]
-
镜像仓库 — docker [login|pull|push|search]
-
本地镜像管理 — docker [build|images|rmi|tag|save|import|load]
-
容器资源管理 — docker [volume|network]
-
系统日志信息 — docker [events|history|logs]
9. Docker镜像(image)
docker hub类似maven远程仓库地址: https://hub.docker.com/
作为一名研发人员,则可以将镜像理解为类(Class)。是一个应用程序。
首先需要先从镜像仓库服务中拉取镜像。常见的镜像仓库服务是 Docker Hub,但是也存在其他镜像仓库服务。
拉取操作会将镜像下载到本地 Docker 主机,可以使用该镜像启动一个或者多个容器。
镜像由多个层组成,每层叠加之后,从外部看来就如一个独立的对象。镜像内部是一个精简的操作系统(OS),同时还包含应用运行所必须的文件和依赖包。
因为容器的设计初衷就是快速和小巧,所以镜像通常都比较小。
前面多次提到镜像就像停止运行的容器(类)。实际上,可以停止某个容器的运行,并从中创建新的镜像。
在该前提下,镜像可以理解为一种构建时(build-time)结构,而容器可以理解为一种运行时(run-time)结构,如下图所示。
10. Docker镜像常用命令
-
pull
-
下载镜像的命令。镜像从远程镜像仓库服务的仓库中下载。默认情况下,镜像会从 Docker Hub 的仓库中拉取。
-
通过下载过程,可以看到,一个镜像一般是由多个层组成,类似 f7e2b70d04ae 这样的串表示层的唯一 ID。
问题一:小伙伴们可能会想到,如果多个不同的镜像中,同时包含了同一个层,这样重复下载,岂不是导 致了存储空间的浪费么? 实际上,Docker 并不会这么傻会去下载重复的层,Docker 在下载之前,会去检测本地是否会有同样 ID 的层,如果本地已经存在了,就直接使用本地的就好了。 问题二:另一个问题,不同仓库中,可能也会存在镜像重名的情况发生, 这种情况咋办? 从严格意义上讲,我们在使用 pull命令时,还需要在镜像前面指定仓库地址(Registry), 如果不指定,则 Docker 会使用您默认配置的仓库地址。例如上面,由于我配置的是国内 docker.io的仓库地址,我在 pull 的时候,docker 会默认为我加上 docker.io/library 的前缀。 例如:当我执行 docker pull tomcat:9.0.20-jre8命令时,实际上相当于 docker pull docker.io/tomcat:9.0.20-jre8,如果您未自定义配置仓库,则默认在下载的时候,会在镜像前面加上 DockerHub 的地址。Docker 通过前缀地址的不同,来保证不同仓库中,重名镜像的唯一性。
常用参数 -a, --all-tags=true|false : 是否获取仓库中所有镜像,默认为否; --disable-content-trust : 跳过镜像内容的校验,默认为 true;
-
-
images
#列出本机已有的镜像 docker images docker image ls 各个选项说明: REPOSITORY:表示镜像的仓库源 TAG:镜像的标签 IMAGE ID:镜像ID CREATED:镜像创建时间 SIZE:镜像大小
-
save
一个镜像
mkdir -p /data cd /data docker save tomcat:9.0.20-jre8-alpine -o tomcat9.tar docker save tomcat:9.0.20-jre8-slim > tomcat9.slim.tar -o :输出到的文件
多个镜像
推荐开发岗的小伙伴使用idea开发工具中的列编辑模式制作docker save命令
mkdir -p /data cd /data docker save \ ubuntu:20.04 \ alpine:3.12.1 \ debian:10.6-slim \ centos:7.8.2003 \ -o linux.tar docker save \ tomcat:9.0.20-jre8-alpine \ tomcat:9.0.20-jre8-slim \ tomcat:9.0.20-jre8 \ -o tomcat9.0.20.tar
-
load
mkdir -p /data cd /data docker load -i linux.tar docker load < tomcat9.0.20.tar 常用参数 --input , -i : 指定导入的文件。 --quiet , -q : 精简输出信息。
-
search
不推荐使用search命令查找镜像,不够直观。
docker search tomcat 常用参数 -f, --filter filter : 过滤输出的内容; --limit int :指定搜索内容展示个数; --no-index : 不截断输出内容; --no-trunc :不截断输出内容;
-
inspect
通过 docker inspect 命令,我们可以获取镜像的详细信息,其中,包括创建者,各层的数字摘要等。
docker inspect 返回的是 JSON格式的信息,如果您想获取其中指定的一项内容,可以通过 -f 来指定,如获取镜像大小
docker inspect tomcat:9.0.20-jre8-alpine docker inspect -f {{".Size"}} tomcat:9.0.20-jre8-alpine
-
history
从前面的命令中,我们了解到,一个镜像是由多个层组成的,那么,我们要如何知道各个层的具体内容呢?
通过 docker history命令,可以列出各个层的创建信息,例如:查看 tomcat:9.0.20-jre8-alpine的各层信息
docker history tomcat:9.0.20-jre8-alpine
-
tag
标记本地镜像,将其归入某一仓库
docker tag tomcat:9.0.20-jre8-alpine qiang/tomcat:9
-
rmi
通过如下两个都可以删除镜像:
docker rmi tomcat:9.0.20-jre8-alpine docker image rm tomcat:9.0.20-jre8-alpine 常用参数 -f, -force : 强制删除镜像,即便有容器引用该镜像; -no-prune : 不要删除未带标签的父镜像;
通过ID删除镜像: 除了通过标签名称来删除镜像,我们还可以通过制定镜像 ID, 来删除镜像。一旦制定了通过 ID 来删除镜像,它会先尝试删除所有指向该镜像的标签,然后在删除镜像本身。
docker rmi ee7cbd482336
推荐通过image的名称删除镜像 image的ID在终端长度未完全显示,ID值会出现重复
删除镜像的限制: 删除镜像很简单,但也不是我们何时何地都能删除的,它存在一些限制条件。当通过该镜像创建的容器未被销毁时,镜像是无法被删除的
1. 先删除引用这个镜像的容器; 2. 再删除这个镜像;
清理镜像: 我们在使用 Docker 一段时间后,系统一般都会残存一些临时的、没有被使用的镜像文件,可以通过以下命令进行清理。执行完命令后,还是告诉我们释放了多少存储空间!
docker image prune 常用参数 -a, --all : 删除所有没有用的镜像,而不仅仅是临时文件; -f, --force :强制删除镜像文件,无需弹出提示确认;
11. Docker容器(container)
容器是镜像的运行时实例。正如从虚拟机模板上启动 VM 一样,用户也同样可以从单个镜像上启动一个或多个容器。虚拟机和容器最大的区别是容器更快并且更轻量级——与虚拟机运行在完整的操作系统之上相比,容器会共享其所在主机的操作系统/内核。下图为使用单个 Docker镜像启动多个容器的示意图。
Docker容器类似于一个轻量级的沙箱,Docker利用容器来运行和隔离应用. 容器是镜像的一个运行实例。
可以将其启动、开始、停止、删除,而这些容器都是彼此相互隔离的、互不可见的。
可以把容器看做是一个简易版的Linux系统环境(包括root用户权限、进程空间、用户空间和网络空间
等)以及运行在其中的应用程序打包而成的盒子
容器是基于镜像启动起来的,容 器中可以运行一个或多个进程。
镜像是Docker生命周期 中的构建或打包阶段,而容器则是启动或执行阶段。
镜像自身是只读的。容器从镜像启动的时候,会在镜像的最上层创建一个可写层。
12. Docker容器常用命令
-
新建并启动容器
docker run [OPTIONS] IMAGE [COMMAND] [ARG...] 例 : docker run -it --rm -p 8080:8080 tomcat:9.0.20-jre8-alpine 常用参数: -d, --detach=false: 后台运行容器,并返回容器ID -i, --interactive=false: 以交互模式运行容器,通常与 -t 同时使用 -t, --tty=false: 为容器重新分配一个伪输入终端,通常与 -i 同时使用 -P, --publish-all=false: 随机端口映射,容器内部端口随机映射到主机的端口。不推荐各位小伙伴 使用该参数 -p, --publish=[]: 指定端口映射,格式为:主机(宿主)端口:容器端口,推荐各位小伙伴们使用 --name="nginx-lb": 为容器指定一个名称 -h , --hostname="laosiji": 指定容器的hostname -e , --env=[]: 设置环境变量,容器中可以使用该环境变量 --net="bridge": 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型 --link=[]: 添加链接到另一个容器;不推荐各位小伙伴使用该参数 -v, --volume : 绑定一个卷 --privileged=false: 指定容器是否为特权容器,特权容器拥有所有的capabilities --restart=no:指定容器停止后的重启策略 no:容器退出时不重启 on-failure:容器故障退出(返回值非零)时重启 always:容器退出时总是重启,推荐各位小伙伴们使用 --rm=false: 指定容器停止后自动删除容器,不能以docker run -d启动的容器
-
容器日志
docker logs [OPTIONS] CONTAINER 例: docker run -itd --name tomcat9 -p 8080:8080 tomcat:9.0.20-jre8-alpine docker logs -f tomcat9 常用参数 -f : 跟踪日志输出 --tail :仅列出最新N条容器日志
-
删除容器
docker rm **:**删除一个或多个容器。docker rm命令只能删除处于终止或退出状态的容器,并不能删除还处于运行状态的容器
docker rm [OPTIONS] CONTAINER [CONTAINER...] 例: docker run -itd --name tomcat9 -p 8080:8080 tomcat:9.0.20-jre8-alpine 需要先停止运行中的容器再删除,否则无法删除容器 docker stop tomcat9 按照容器名称删除 docker rm tomcat9 按照容器ID删除 docker rm 8dd95a95e687 常用参数 -f :通过 SIGKILL 信号强制删除一个运行中的容器。 -l :移除容器间的网络连接,而非容器本身。 -v :删除与容器关联的卷。
-
列出容器
docker ps [OPTIONS] 例: docker run -itd --name tomcat9 -p 8080:8080 tomcat:9.0.20-jre8-alpine 查看运行中的容器 docker ps tomcat9 查看所有容器 docker ps -a tomcat9 常用参数 -a :显示所有的容器,包括未运行的。 -q :只显示容器编号。
输出详情介绍:
CONTAINER ID: 容器 ID。
IMAGE: 使用的镜像。
COMMAND: 启动容器时运行的命令。
CREATED: 容器的创建时间。
STATUS: 容器状态。
状态有7种: created(已创建) restarting(重启中) running(运行中) removing(迁移中) paused(暂停) exited(停止) dead(死亡)
PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。
NAMES: 自动分配的容器名称。
#实用技巧 停止所有运行容器 docker stop $(docker ps -qa) 删除所有的容器 docker rm $(docker ps -aq) docker rm $(docker stop $(docker ps -q)) 删除所有的镜像 docker rmi $(docker images -q)
-
创建容器
#创建一个新的容器但不启动它。用法同 docker run命令 docker create [OPTIONS] IMAGE [COMMAND] [ARG...] docker create -it --name tomcat9 -p 8080:8080 9.0.20-jre8-alpine
-
启动,重启,终止容器
docker start :启动一个或多个已经被停止的容器 docker stop :停止一个运行中的容器 docker restart :重启容器 docker start [OPTIONS] CONTAINER [CONTAINER...] docker stop [OPTIONS] CONTAINER [CONTAINER...] docker restart [OPTIONS] CONTAINER [CONTAINER...] 例: docker start tomcat9 docker stop tomcat9 docker restart tomcat9
-
进入容器
docker exec **:**在运行的容器中执行命令。早期有attach命令,对于阻塞命令会等待,所以不方便。在Docker 1.3.0后提供了exec 可以在容器内直接执行任意命令
docker exec [OPTIONS] CONTAINER COMMAND [ARG...] 例: 有bash命令的linux系统:例如centos docker run -it --name tomcat9.1 -p 8080:8080 tomcat:9.0.20-jre8-slim docker exec -it tomcat9.1 /bin/bash 没有bash命令的linux系统:例如alpine系统 docker run -it --name tomcat9.2 -p 8081:8080 tomcat:9.0.20-jre8-alpine docker exec -it tomcat9.2 sh 常用参数 -i :即使没有附加也保持STDIN 打开 -t :分配一个伪终端
-
查看容器
docker inspect : 获取容器/镜像的元数据。
docker inspect [OPTIONS] NAME|ID [NAME|ID...] 例: docker run -it --name tomcat9 -p 8081:8080 tomcat:9.0.20-jre8-alpine docker inspect tomcat9 常用参数 -f :指定返回值的模板文件。 -s :显示总的文件大小。 --type :为指定类型返回JSON。
-
更新容器
docker update :可以动态地更新容器配置。可以更新一个或多个容器配置。多个容器名称或ID之间使用空格分隔。但update命令不是很成熟,有很多配置项不能动态更新。推荐大家还是rm容器后,再重新run一个新的镜像
docker update [OPTIONS] CONTAINER [CONTAINER...] 例: docker run -it --name tomcat9 -p 8081:8080 tomcat:9.0.20-jre8-alpine 更新容器restart策略 docker update --restart always tomcat9
-
杀掉容器
docker kill [OPTIONS] CONTAINER [CONTAINER...] 例: docker run -it --name tomcat9 -p 8081:8080 tomcat:9.0.20-jre8-alpine docker kill tomcat9 docker ps docker ps -a docker start tomcat9 常用参数 -s :向容器发送一个信号
13. Docker常用命令汇总
14. 常用软件安装示例
-
安装nginx
# 拉取镜像 docker pull nginx:1.19.3-alpine # 备份镜像 docker save nginx:1.19.3-alpine -o nginx.1.19.3.alpine.tar # 导入镜像 docker load -i nginx.1.19.3.alpine.tar # 运行镜像 docker run -itd --name nginx -p 80:80 nginx:1.19.3-alpine 进入容器 docker exec -it nginx sh 查看html目录 cd /usr/share/nginx/html 配置文件目录 cat /etc/nginx/nginx.conf
-
安装mysql
docker pull mysql:5.7.31 #学习docker run -e参数 -e , --env=[]: 设置环境变量,容器中可以使用该环境变量 官网中给出进入容器的第三种方式,前边我们学习了/bin/bash,sh 向my.cnf文件中追加相关配置项 docker run -itd --name mysql --restart always --privileged=true -p 3306:3306 -e MYSQL_ROOT_PASSWORD=admin mysql:5.7.31 --character-set-server=utf8 --collation-server=utf8_general_ci
-
privileged参数
我们大多数熟悉 Unix 类系统的人,都习惯于通过使用 sudo 来随意提升自己的权限,成为 root 用户。我们在使用 Docker 容器的过程中知道,docker提供了一个 –privileged 的参数,其实它与随意使用sudo 有很大的不同,它可能会让你的应用程序面临不必要的风险,下面我们将向你展示这与以 root 身份运行的区别,以及特权的实际含义。
作为 Root 运行 Docker 允许在其宿主机上隔离一个进程、capabilities 和文件系统,但是大多数容器实际上都是默认以 root 身份运行。这里我们拿 DockerHub 上几个比较流行的镜像来进行说明。 避免以 root 运行 虽然在容器内以 root 身份运行是很正常的,但如果你想加固容器的安全性,还是应该避免这样做。 特权模式 --privileged 可以不受限制地访问任何自己的系统调用。在正常的操作中,即使容器内有 root, Docker 也会限制容器的 Linux Capabilities 的,这种限制包括像 CAP_AUDIT_WRITE 这样的东西, 它允许覆盖内核的审计日志--你的容器化工作负载很可能不需要这个 Capabilities。所以特权只应该在你 真正需要它的特定设置中使用,简而言之,它给容器提供了几乎所有主机(作为root)可以做的事情的权 限。 本质上,它就是一个免费的通行证,可以逃避容器所包含的文件系统、进程、sockets 套接字等,当然 它有特定的使用场景,比如在很多 CI/CD 系统中需要的 Docker IN Docker 模式(在 Docker 容器内部 需要 Docker 守护进程),以及需要极端网络的地方。
-
测试mysql
进入容器:根据官网上的实例,使用bash命令进入容器 docker exec -it mysql bash 登录mysql mysql -uroot -p 输入密码 admin use mysql; show databases; 退出mysql exit 退出容器 exit
-
-
其他………………