Docker是一个开源的应用容器引擎,开发者可以打包应用和依赖包(运行环境)到一个可移植的镜像中,然后发布到任何一个Linux或者Windows上。容器之间是独立的沙盒机制,相互之间没有任何接口。
在项目开发中,总是会因为环境配置做许多重复性的工作,比如操作系统的配置,node环境的配置,各种依赖文件需要下载等,于是Docker出现,通过Dockerfile
配置文件便可以将你所需要的环境生成出来,至此开发者可以不必再关心开发前与开发后的各种配置,仅专注于程序开发即可。
基本概念
- 镜像(Image): 相当于一个root文件系统,比如一个ubuntu系统可一个作为一个镜像使用。镜像是用于创建Docker容器的模板。
- 容器(Container):
用来承载你需要运行的项目的东西。镜像之于容器,就像JavaScript里的类之于实例:
const container = new Image()
,镜像是静态的定义,容器是镜像运行的实体。 - 仓库(Repository): 用来保存镜像的仓库系统,比如你创建一个自己的专属镜像,然后上传到镜像仓库,上传后的镜像可以给其他人时候用。
应用场景
- Web应用的自动化打包和发布。
- 自动化测试和持续集成、发布。
- 在服务型环境中部署和调整数据库或其他的后台应用。
创建一个基本的Docker应用
1. 下载镜像
# 查看已下载的镜像
docker images
# 在https://hub.docker.com/搜索镜像
docker search node
# 下载一个最新版本的node镜像,如果想选择版本,那么镜像名写node:16.04。
docker pull node
# 删除镜像,参数可以是镜像名称,也可以是镜像id
docker rmi node
# 强制删除
docker rmi -f node
2. 创建Dockerfile文件
在项目根目录创建Dockerfile文件,根据一个基础镜像定制一个你想要的系统镜像,示例:
# 基础镜像
FROM node:latest
# 指定后续命令的用户
USER root
# 将当前目录下的所有文件(除了.dockerignore排除的路径)复制到镜像的/app目录
COPY . /app
# 指定后续的工作路径
WORKDIR /app
RUN npm i
# 将容器3000端口暴露出来,允许外部访问
EXPOSE 3000
# 起web服务
ENTRYPOINT ["npm", "run"]
CMD ["start"]
3. 构建镜像
语法:docker build [OPTIONS] PATH | URL | -
# 构建一个镜像名为react-app、标签名为pro的镜像
docker build -t react-app:pro .
# -f 是指定文件名为dev.Dockerfile的Dockerfile来构建镜像。
docker build -t react-app:dev -f dev.Dockerfile .
上面的命令有个.
,这是个什么鬼???它指的是本次执行的上下文路径,可以指定Dockerfile 的绝对路径,由于docker的运行模式是C/S。我们本机是C,docker 引擎是 S。实际的构建过程是在docker引擎下完成的,所以这个时候无法用到我们本机的文件,比如我们想copy文件到镜像系统里。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。
3. 运行(创建)容器
命令:docker run -p 4000:3000 -it -d react-app:pro
start。
其中几个参数的作用如下:
- run:创建一个新的容器并运行一个命令,会返回创建的容器id;
- -p:用来将容器内部端口暴露给外部端口的参数,其中4000是外部端口,3000是内部端口,所以上述应用访问地址为http://localhost:4000;
- -it:容器的Shell映射到当前的Shell,然后你在本机窗口输入的命令,就会传入容器;
- -d:在后台运行容器。如果你不想每个容器都占用一个终端窗口,这个参数会对你有帮助;
- start:在镜像名称后面的参数是传入到容器内部的参数,这个参数是传给Dockerfile里的
CMD
,CMD命令有个默认值,如果不传这个参数会使用默认值运行命令。
如果你不想指定某个端口来访问容器内部端口,那么使用-P
参数可以自动随机映射EXPOSE
的端口:docker run -P -it -d react-app:pro
,然后输入docker ps -a
查看容器运行在了哪个端口上:
4. 查看应用
这时候打开浏览器访问http://localhost:4000,可以看到运行在docker中的应用啦~
5. 发布image
把上述步骤生成的镜像发布到docker上,在hub.docker.com/上注册一个用户,登录:
docker login
为本地镜像标注用户名和版本:
# docker image tag [imageName] [username]/[repository]:[tag]
docker image tag react-app:pro urnotzane/react-app:1.0.0
发布镜像文件:
# docker image push [username]/[repository]:[tag]
docker image push urnotzane/react-app:1.0.0
发布成功以后就可以在自己的用户页面看到自己发布的镜像了,本文镜像示例地址是urnotzane/react-app
分层结构
在Dockerfile中的每一行命令,都在Docker镜像层中以一个独立镜像层的形式存在,因此减少镜像层是一个优化镜像提及的好方法。镜像层最底层为最基础的系统镜像,然后是Dockerfile的命令形成的层,然后是容器的初始层,最后最顶层是容器所在的可读写层。如下图:
使用docker history [Image Name]
可以查看历史镜像结构,拿本文所创建的镜像举例:
我们可以看到,Dockerfile里的每一个指令都会生成一个镜像,Docker的缓存就是缓存这些指令生成的镜像,所以一个Dockerfile文件里的指令越多,它生成的镜像文件就越大。
换个角度讲,如果Dockerfile的第N个指令的内容或指令涉及的文件内容发生了变更,那么后续的命令都会重新执行,而不会去取缓存的镜像,所以要想加速构建速度,可以从这个方面去优化。
Dockerfile解析
CMD
会被docker run的命令参数所覆盖,类似于RUN指令,不同之处是执行时间不同:
- RUN是在docker build时运行;
- CMD是在docker run时运行。
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。如果Dockerfile存在多个CMD则只有最后一个会生效。
ENTRYPOINT
docker run的命令行参数会作为参数来传给ENTRYPOINT指令指定的程序,除非在docker run命令行使用了--entrypoint
选项。
可搭配CMD使用,这里的CMD就是ENTRYPOINT的执行参数,比如:
...
ENTRYPOINT ["npm", "run"]
CMD ["start"]
不传参运行docker run -P -it -d react-app:pro
时是npm run start
,传参如docker run -P -it -d react-app:pro build
时,运行的则是npm run build
。
ENV
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
...
ENV NODE_ENV production
RUN echo ${NODE_ENV}
ARG
构建参数,与 ENV 作用一至。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有docker build的过程中有效,构建好的镜像内不存在此环境变量。
构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。
...
ARG USERNAME=''
ARG PASSWORD=''
RUN echo ${USERNAME} && echo ${PASSWORD}
...
覆盖命令:docker build -t react-app:arg --build-arg USERNAME=zane --build-arg PASSWORD=123456 .
WORKDIR
WORKDIR指令设置Dockerfile中的任何RUN,CMD,ENTRPOINT,COPY和ADD指令的工作目录。如果WORKDIR指定的目录不存在,即使随后的指令没有用到这个目录,都会创建。
USER
用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
COPY
复制指令,从上下文目录中复制文件或者目录到容器里指定路径。目录不存在时会自动创建。
优缺点
docker与虚拟机
- 虚拟机如VMware之类需要模拟整台机器包括硬件环境,每台虚拟机都有完整的操作系统,一旦将资源预分配给虚拟机,那么这些资源将全部被占用;而docker容器不是模拟一个完整的操作系统,而是对进程进行隔离。(Hypervisor:虚拟机监视器(virtual machine monitor,缩写为 VMM),是用来创建与运行虚拟机的软件、固件或硬件。)。但是具体到底是怎么个隔离法还需深入研究,这里篇幅有限就先搁置。
- Docker将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了Docker,就不用担心环境问题。
- 容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。
优点
- 操作系统级别虚拟化,容器和内核交互,几乎无性能损耗。
- 更轻量,各镜像共用一个内核与共享应用程序库,所占内存小。
- 占用硬盘一般为MB,而虚拟机GB级别。
- 高可用性,可快速重新部署。
- 分钟级别虚拟化创建,秒级别容器创建。
- Dockerfile记录容器构建过程,可在集群中实现快速分发和部署。
- 持续集成性高,通过编辑Dockerfile文件自动拉取代码、编译构建、运行测试、结果记录、测试统计。
缺点
- 隔离性较弱,Docker属于进程间的隔离,虚拟机属于系统级别的隔离。
- 安全性较弱,一旦容器内的用户提升为root,它就直接具备了宿主机的root权限。
常用命令
- 创建容器
# 创建运行一个可交互式的容器 docker run -it react-app:pro /bin/bash # 创建并后台运行一个可交互式的容器 docker run -itd react-app:pro /bin/bash # 查看所有容器 docker ps -a # 退出容器终端 exit # 查看运行中的容器 docker ps
- 启动容器
# 启动已停止的容器 docker start <Container ID/NAME> # 重启容器 docker restart <Container ID/NAME>
- 停止容器
# 停止运行中的容器 docker stop <Container ID/NAME>
- 进入容器
# 退出容器会停止容器:docker attach [OPTIONS] CONTAINER docker attach <Container ID> # 退出容器不会停止容器 docker exec -it <Container> /bin/bash
- 删除容器
# 删除指定容器 docker rm -f <Container ID> # 清除所有终止状态的容器 docker container prune
- 运行web应用
# 运行容器并暴露内部端口至随机端口 docker run -itd -P react-app:pro # 运行容器并暴露内部端口至指定端口 docker run -itd -p 32768:3000 react-app:pro # 查看内部输出日志 docker logs -f <Container ID/NAME> # 查看内部运行进程 docker top <Container ID>
- 镜像清理
有时候由于调试代码产生很多的none的image,挨个清理会有些麻烦,下面是全部清理的命令:
# 列出所有容器ID docker ps -aq # 停止所有容器 docker stop $(docker ps -aq) docker ps -a | grep "Exited" | awk '{print $1 }'|xargs docker stop # 删除所有停止的容器 docker ps -a | grep "Exited" | awk '{print $1 }'|xargs docker rm # 删除所有容器 docker rmi $(docker ps -aq) # 删除所有tag标签是none的镜像 docker images|grep none|awk '{print $3 }'|xargs docker rmi
- 更新镜像
在运行的容器内使用docker run -it node:latest /bin/bash
apt-get update
命令进行更新。
遇到的问题
- docker run -p 4000:3000 -d react-app:pro start,其中-d是后台运行容器的意思,但是总是会直接退出,这是因为Docker在
npm run start
还没运行成功的时候检测到这个容器内没有运行中的前台应用,为了节省资源就给这个容器退出了(参考)。加个-it
等待npm run start
运行成功后,docker检查到你有运行一个前台应用,那么这个容器就不会被退出了。
参考
- Docker的使用
- Docker教程 | 菜鸟教程
- Docker入门教程 - 阮一峰
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!