Docker可以方便部署以及利用镜像快速学习一些项目,解决环境冲突等.重点关注Dockerfile和docker-compose文件的编写.
核心概念
Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。
Docker 是一个用于开发,交付和运行应用程序的开放平台。Docker 使您能够将应用程序与基础架构分开,从而可以快速交付软件。借助 Docker,您可以与管理应用程序相同的方式来管理基础架构。通过利用 Docker 的方法来快速交付,测试和部署代码,您可以大大减少编写代码和在生产环境中运行代码之间的延迟。
- Web 应用的自动化打包和发布。
- 自动化测试和持续集成、发布。
- 在服务型环境中部署和调整数据库或其他的后台应用。
- 从头编译或者扩展现有的 OpenShift 或 Cloud Foundry 平台来搭建自己的 PaaS 环境。
镜像(image)
镜像类似于一个打包好的软件或可执行程序,可以通过运行这个镜像得到容器(类似于一个进程).
镜像可以自己打包或从Docker HubDocker Hub Container Image Library | App Containerization获取,如果本地没有打包的默认从后者拉取.
自己打包需要Dockerfile定制这个”可执行程序”,有了Dockerfile后可以使用docker build .
构建镜像.
.
符号表示在这个目录下的Dockerfile文件.
一个镜像可以在多个容器运行,可以将镜像分享给别人.
使用docker run
运行镜像,如果本地没有会自动docker pull
拉取.
使用docker push
可以将自己的镜像推送到Docker Hub.
这里我们创建一个小项目.
创建一个服务监听端口.
1
2
3
4
5
6
7
8
9
10const express = require('express');
const app = express();
const port = 3000;
app.get('/',(req,res)=>
{
res.send('<p>你好</p>')
});
app.listen(port,()=>console.log("端口是3000"))
写好后就可以直接创建Dockerfile建立镜像了.
首先Dockerfile文件创建在项目根目录中.
需要先拉取镜像,可以在Docker Hub Container Image Library | App Containerization中查找.
首先我们用到了node,所以需要拉取相应的node镜像(一般node镜像肯定带了OS等底层的镜像)
1
2
3
4
5
6
7FROM node:19-alpine3.16
WORKDIR /myworkdir
COPY package.json .
RUN npm i
COPY . .
EXPOSE 3000
CMD ["node","app.js"]
docker会一行一行扫描代码.
FROM表示拉取node:19-alpine3.16,node:19-alpine3.16是镜像名,19-alpine3.16表示版本,node 19版本,alpine是一个操作系统常用于Docker构建.1
docker build -t myimage:v1 .
如果不使用tag,则没有名字
1
docker tag <IMAGE ID> <REPO:TAG>
没有tag默认latest
使用docker push
推送镜像
使用docker rmi
删除本地镜像
使用docker pull
拉取Docker Hub中的镜像.
容器(container)
使用docker run <镜像名>
运行镜像从而得到
-d
参数后台运行
使用docker images
查询镜像信息.
使用docker ps
查询容器信息.
这里并不能直接通过3000端口访问网页,因为并没有实际暴露.
Dockerfile文件中EXPOSE命令只是标识提醒作用.1
docker run -d -p 3000:3000 --name mydocker proanimer/nodejs:test
-p
参数表示端口映射 本地3000映射后者容器的3000.
--name
参数表示给容器命名,否则有默认命名.1
docker run -d -p 3000:3000 --name mydockerpro proanimer/nodejs:test
使用docker stop <容器id>
停止运行.
使用docker rm <容器id>
删除窗口.
修改文件后容器并不会跟着改变,因为修改的文件时本地镜像中的文件,容器是之前的镜像运行后的结果.我们需要与运行的容器直接交互.
使用docker exec -it <镜像名或id> /bin/sh
/bin/sh
是容器中os的shell.
注意 如果在Windows上需要加上winpty,同时设定shell路径时是//bin/sh
即需要多加上一个/
注意进入容器后很多工具比如vim可能都没有,所以需要用到路径映射.
设置volume,-v 把本地指定文件夹和容器指定文件夹绑定
这里使用
注意如果是git bash for windows.使用下面命令,1
docker run -d -v F://docker_exp1://myworkdir -p 3000:3000 --name mypro proanimer/nodejs:test
发现挂载路径有/hostmnt,这是git bash比较特别的,表示宿主机.
如果是在windows的powershell.
检查挂载路径,
两者这里不同,但本质上是一样的.
注意,这里路径映射时是依照宿主机的,即如果宿主机/dir上有A,B文件,容器路径中/dir中有C文件,将这两个路径映射,则实际用时是A,B文件.
同时使用-v 目录
对这个容器中的目录不进行同步.本地只读后增加:ro
ro模式
(1)文件:容器内不能修改,会提示read-only
(2)文件夹:容器内不能修改、新增、删除文件夹中的文件,会提示read-only
docker rm -fv
同时把volume删除.
Dockerfile
通过写Dockerfile定制镜像文件,使用docker build
创建镜像.
FROM
FROM:定制的镜像都是基于FROM的镜像
RUN
RUN:用于执行后面跟着的命令行命令。有以下两种格式:
shell 格式:1
2RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。
exec 格式:1
2
3RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline
注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:1
2
3
4FROM centos
RUN **yum** -y **install** **wget**
RUN **wget** -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN **tar** -xvf redis.tar.gz
以上执行会创建 3 层镜像。可简化为以下格式:1
2
3
4FROM centos
RUN yum -y install wget \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& tar -xvf redis.tar.gz
如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。
CMD
类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
- CMD 在docker run 时运行。
- RUN 是在 docker build即构建时运行.
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。1
2
3CMD <shell 命令>
CMD ["<可执行文件或命令>","<param1>","<param2>",...]
CMD ["<param1>","<param2>",...] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
ENTRYPOINT
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
但是, 如果运行 docker run 时使用了 —entrypoint 选项,将覆盖 ENTRYPOINT 指令指定的程序。
优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。
注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。1
ENTRYPOINT ["<executeable>","<param1>","<param2>",...]
WORKDIR
指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。
docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。
格式:1
WORKDIR <工作目录路径>
VOLUME
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
作用:
- 避免重要的数据,因容器重启而丢失,这是非常致命的。
- 避免容器不断变大。
格式:1
2VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
EXPOSE
仅仅只是声明端口. 注意并没有实际作用
作用:
- 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
- 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
格式:1
EXPOSE <端口1> [<端口2>...]
ENV
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
格式:1
2ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:1
2
3
4ENV NODE_VERSION 7.2.0
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"
ARG
构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
构建命令 docker build 中可以用 —build-arg <参数名>=<值> 来覆盖。
格式:1
ARG <参数名>[=<默认值>]
ONBUILD
用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。
格式:1
ONBUILD <其它指令>
LABEL
LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:1
LABEL <key>=<value> <key>=<value> <key> =<value> ...
比如我们可以添加镜像的作者:1
LABEL org.opencontainers.image.authors="runoob"
docker-compose
启动多个容器处理应用.
yaml文件格式.
基本语法
- 大小写敏感
- 使用缩进表示层级关系
- 缩进不允许使用tab,只允许空格
- 缩进的空格数不重要,只要相同层级的元素左对齐即可
- ‘#’表示注释
创建docker-compose.yml文件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# yaml 配置实例
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
- logvolume01:/var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}
services下都是镜像,build表示通过Dockerfile构建.
ports和volumes用于映射端口和数据卷.
使用命令docker-compose up -d --build
-d表示后台,—build表示如果镜像修改就会重建.
version
指定本 yml 依从的 compose 哪个版本制定的。
build
指定为构建镜像上下文路径:
volumes
将主机的数据卷或着文件挂载到容器里。1
2
3
4
5
6
7version: "3.7"
services:
db:
image: postgres:latest
volumes:
- "/localhost/postgres.sock:/var/run/postgres/postgres.sock"
- "/localhost/data:/var/lib/postgresql/data"
expose
暴露端口,但不映射到宿主机,只允许能被连接的服务访问。仅可以指定内部端口为参数,如下所示:1
2
3expose:
- "3000"
- "8000"
links
链接到其它服务中的容器。使用服务名称(同时作为别名),或者服务名称:服务别名(如 SERVICE:ALIAS),例如1
2
3
4links:
- db
- db:database
- redis
使用docker-compose down -v
删除镜像同时删除volume