什么是Docker
Docker是一种新兴的虚拟化方式,基于Go语言实现的开源项目,诞生于2013年初。
Docker底层基于成熟的Linux Container(LXC)技术实现,自Docker 0.9版本起,引入libcontainer, 打造更通用的底层容器虚拟化库,依赖的底层核心技术主要包括了操作系统命名空间(namespace)、控制组(Control Groups)、联合文件系统(Union File Systems)和 虚拟网络.
为什么使用Docker
- 更快速的交付和部署
- 更高效的资源利用
- 更轻松的迁移和扩展、维护
基础概念
Docker 主要包括三个基本概念:
- 镜像:类似于虚拟机镜像,可以理解成Docker引擎的只读模板,是创建Docker容器的基础
- 容器:类似于一个轻量级的沙箱,Docker利用容器来运行和隔离应用,容器依赖镜像,一个镜像可以运行多个容器
- 仓库:存放镜像文件的场所,比如Docker hub
Docker常用命令
docker命令
docker --help //该命令可以查看docker详细命令
镜像搜索
docker search java
拉取镜像
docker pull java:8 //docker pull REPOSITORY[:TAG],不填版本号默认拉取最新版
镜像列表
docker images //列出镜像列表
删除镜像
docker rmi java:8 //删除镜像,-f 参数代表强制删除
注意:删除镜像应该先删除镜像关联的容器,再删除镜像
创建和运行容器
docker run --name web1 -d -p 8080:80 nginx:v1 //命令详细 docker run --help
常用参数说明:
- -t 选项让Docker分配一个伪终端(pseudo-tty) 并绑定到容器的标准输入上
- -i 则让容器的标准输入保持打开
- -d 后台运行
- -p 映射端口 本地端口:容器端口
- -P 随机映射端口
- -name 指定容器名称
- --rm 退出后自动删除
- -v 挂载数据卷 例如:
-v /var/log/demo:/log
挂载主机目录/var/log/demo
容器启停
docker start web1 // 启动 docker start 容器id/容器name
docker stop web1 // 停止 docker stop 容器id/容器name
列出容器
docker ps //列出正在运行的容器
docker ps -a //列出所有的容器
进入容器
docker exec -it web1 /bin/bash
删除容器
docker rm web1
docker rm $(docker ps -aq) //删除所有容器
docker rm $(docker ps -a|grep demo|awk '{print $1}') //按关键字demo过滤删除容器
获取容器元数据
docker inspect web1
查看容器日志
docker logs web1
基于容器创建镜像
docker commit web1 test/web1:v1 //命令详细 docker commit --help
上传镜像
docker tag web1:v1 user/web1:v1 //镜像打标签(实际创建一个新的镜像)
docker push user/web1:v1 //上传镜像
Dockerfile创建镜像
具体参见官网:https://docs.docker.com/engine/reference/builder/
案例
a. 创建目录
mkdir springbootdemo
cd springbootdemo
vi Dockerfile
b. 创建dockerfile文件:
FROM java:8
MAINTAINER 作者名 邮箱地址
COPY demo1.jar /demo.jar
RUN java -version
EXPOSE 8080
ENV active ''
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/demo.jar","--spring.profiles.active=${active}"]
c. 上传jar包到springbootdemo 目录下
d. 构建镜像
docker build -t demo:v1 . //springbootdemo目录下构建镜像
e. 运行容器
docker run -d -P --name=demo1 -e active="test" demo:v1 //传递参数active="test"
指令说明
FROM
格式为 FROM <image> 或者 FROM <image>:<tag>
必须为第一条指令
MAINTAINER
指定维护者 信息
RUN
格式:RUN <command> 或者 RUN ["executable","param1","param2"]
该命令可以多条,创建镜像时执行的命令,当命令较长时可以使用** \ ** 来换行
CMD
CMD ["executable","param1","param2"]
CMD commond param1 param2
CMD ["param1","param2"] //提供给ENTRYPOINT的默认参数
指定容器启动时执行的命令,每个docker只能有一条CMD命令,如果多条的话,只会执行最后一条,如果用户启动容器指定了运行的命令,则会覆盖CMD命令
EXPOSE
格式 EXPOSE <port> [<port>...]
指定容器暴露的端口号
ENV
格式 ENV <key> <value>
指定环境变量,多个变量多条ENV指令,可以被后续的指定使用${key}
ADD/COPY
格式: ADD <src> <dest> ; COPY <src> <dest>
该命令复制指定src 到容器中dest,其中 src 是dockerfile坐在目录的一个相对路径(文件或者目录),目标路径不存在时会自动创建,两个区别在于,ADD 的src 支持URL,ADD src 是 tar文件会自动解压为目录,推荐使用COPY指令
ENTRYPOINT
ENTRYPOINT ["executable","param1","param2"]
ENTRYPOINT commond param1 param2 //shell中执行
配置容器启动后执行的命令,并且不可被docker run 提供的参数覆盖,只能有一个ENTRYPOINT,当多个时,只有最后一个生效
VOLUME
格式为VOLUME ["/data"]
创建一个挂载点,/data 代表容器中的目录,用于存放需要保持的数据
USER
格式:USER <user>[:<group>] 或者 USER <UID>[:<GID>]
WORKDIR
格式1:WORKDIR /path/to/workdir
格式2:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd //结果/a/b/c
RUN 与 CMD 区别
RUN 是创建镜像执行的命令可以多条,CMD是启动容器执行的命令只有最后一条生效
CMD 与 ENTRYPOINT 区别
1.两者多条命令只有最后一条生效;
2.CMD 可由 docker run <image> 后的命令覆盖,同时覆盖参数,但是定义了ENTRYPOINT docker run <image> 后的命令全是参数;
3.CMD 与 ENTRYPOINT 同时定义,CMD追加ENTRYPOINT参数后面当参数
举四个例子进行说明
一, 未定义 ENTRYPOINT, 定义了 CMD
#ENTRYPOINT []
CMD ["echo", "hello"]
实际入口是它们拼接后还是 CMD 本身,["echo", "hello"]
二, 定义了 ENTRYPOINT 和 CMD
ENTRYPOINT ["echo", "hello"]
CMD ["echo", "world"]
实际入口是它们拼接起来,形成 ["echo", "hello", "echo", "world"], 执行 docker run test 显示为 hello echo world
三, 定义了 ENTRYPOINT, CMD 由 docker run 提供
ENTRYPOINT ["echo", "hello"]
执行命令
docker run <image> rm -rf /
, 实际入口是由["echo", "hello"]
与["rm", "-rf", "/"]
拼接而成的["echo", "hello", "rm", "-rf", "/"]
, 输出为hello rm -rf /
。看到rm -rf /
也不用担心,用 ENTRYPOINT 就是让人放心
注:ENTRYPOINT 同样可以被覆盖,如 docker run --entrypoint ls test -l /
,将会执行 ls -l /
命令。
建议ENTRYPOINT 固定命令,docker run <image>后面传参数
四, 如果 ENTRYPOINT 用 shell 格式定义的
ENTRYPOINT java -jar /app.jar
CMD ["hello", "world"]
通过 docker inspect 命令看到镜像中实际的 ENTRYPOINT 是
ENTRYPOINT ["/bin/sh", "-c", "java -jar /app.jar"]
所以与 CMD 连接起来的入口就是 ["/bin/sh", "-c", "java -jar /app.jar", "hello", "world"], "bin/sh" 直接忽略掉后面的 "hello" 与 "world",这就是为什么 shell 命令方式无法获取参数。
-
未定义 ENTRYPOINT
没有定义 ENTRYPOINT 的镜像想怎么来就怎么来,docker run <image> 后面的输入你自己作主。 -
有定义 ENTRYPOINT
定义了 ENTRYPOINT 的镜像,则是 CMD 或 docker run <image> 后的输入作为 ENTRYPOINT 中命令的附加参数。再次提醒 shell 格式的 ENTRYPOINT 和 CMD 务必要转换为相应 exec 格式来理解。 -
shell 格式的 ENTRYPOINT
如果是复杂的 shell 命令不容易拆解出一个个参数,而希望用 shell 格式来定义 ENTRYPOINT 的话,也有办法。shell 格式的 ENTRYPOINT 是由"/bin/sh -c"
启动的,而它是可以解析变量的。另一方面 CMD 或 docker run <image> 的输入第一个元素存成了$0
,其他剩余元素存为$@
, 所以 shell 格式的 ENTRYPOINT 可以这么写ENTRYPOINT echo hello $0 $@
(shell 中$0
表示命令本身,$@
为所有参数)这样执行下面 docker 命令将可获得所有的参数输入
$ docker run test world and China hello world and China
如果只是按常规 shell 脚本来对待,想当然的写成
ENTRYPOINT echo hello $@
效果将是$ docker run test world and China hello and China
第一个参数将被丢失,docker run <image> 后第一个输入通常是一个命令,所以是
$0
, 而 ENTRYPOINT 又希望它是一个普通参数,因此$0 $@
要同时写上。
容器数据管理
数据卷
docker run -d -P --name demo1 -v /data demo:v1 //创建一个数据卷挂载到容器/data目录
docker run -d -P --name demo1 -v /opt/data:/data demo:v1 //挂载主机的/opt/data目录到容器的/data 目录
数据卷容器
docker run -it -v /dbdata --name dbdata ubuntu //数据卷容器
docker run -it --volumes-from dbdata --name db1 ubuntu
docker run -it --volumes-from dbdata --name db2 ubuntu
--volumes-from 容器name, db1,db2 挂载到同一数据卷,三个容器任务一方在该目录下的写入,其它容器都可见,其实就是操作同一目录文件
docker volume ls //查看所有数据卷,详见:docker volume --help
备份
docker run --volumes-from dbdata -v $(pwd):/backup --name db1 ubuntu tar cvf /backup/backup.tar /dbdata
恢复
docker run --volumes-from dbdata -v $(pwd):/backup --name db2 ubuntu tar xvf /backup/backup.tar
容器与主机文件拷贝
docker cp /opt/test.txt demo1:/opt/test //主机copy to 容器
docker cp demo1:/opt/test /opt //容器copy to 主机
Docker目录结构
默认存储目录 Docker Root Dir:
/var/lib/docker
,存储镜像和容器的元数据以及运行数据,有两种修改方式
1.修改配置文件:/usr/lib/systemd/system/docker.service
里面 ExecStart=/usr/bin/dockerd --graph=/home/docker/lib/docker
通过--graph
参数修改默认存储目录
- 配置目录:
/etc/docker/daemon.json
配置镜像地址,指定存储目录
{
"registry-mirrors":["地址1","地址2"],
"data-root":"/cache1/docker"
}
网友评论