阅读更多
1 安装docker
1.1 centos
1 | # docker安装 |
2 容器的生命周期
3 文件系统
3.1 overlay2
Example OverlayFS Usage [duplicate]
4 创建镜像
创建一个空的目录,例如/tmp/test
创建Dockerfile(核心)
- FROM:用于指定一个基础镜像
- 一般情况下一个可用的Dockerfile一定是FROM作为第一个指令。至于image则可以是任何合理存在的image镜像
FROM
一定是首个非注释指令DockerfileFROM
可以在一个Dockerfile中出现多次,以便于创建混合images- 如果没有指定tag,latest将会被指定为要使用的基础镜像版本
- MAINTAINER:用于指定镜像制作者的信息
- RUN:创建镜像时执行的命令(RUN命令产生的作用是会被持久化到创建的镜像中的)
- 层级
RUN
指令和生成提交是符合Docker核心理念的做法。它允许像版本控制那样,在任意一个点,对image镜像进行定制化构建 RUN
指令缓存不会在下个命令执行时自动失效。比如RUN apt-get dist-upgrade -y
的缓存就可能被用于下一个指令--no-cache
标志可以被用于强制取消缓存使用
- 层级
- ENV:用于为docker容器设置环境变量
ENV
设置的环境变量,可以使用docker inspect
命令来查看。同时还可以使用docker run --env <key>=<value>
来修改环境变量
- USER:用来切换运行属主身份
- Docker默认是使用root
- WORKDIR:用于切换工作目录
- Docker默认的工作目录是
/
,只有RUN
能执行cd命令切换目录,而且还只作用在当下的RUN
,也就是说每一个RUN
都是独立进行的 - 如果想让其他指令在指定的目录下执行,就得靠
WORKDIR
,WORKDIR
动作的目录改变是持久的,不用每个指令前都使用一次WORKDIR
- Docker默认的工作目录是
- COPY:将文件从路径
<src>
复制添加到容器内部路径<dest>
<src>
必须是想对于源文件夹的一个文件或目录,也可以是一个远程的url<dest>
是目标容器中的绝对路径- 所有的新文件和文件夹都会创建UID和GID。事实上如果
<src>
是一个远程文件URL,那么目标文件的权限将会是600
- ADD:将文件从路径
<src>
复制添加到容器内部路径<dest>
<src>
必须是想对于源文件夹的一个文件或目录,也可以是一个远程的url<dest>
是目标容器中的绝对路径- 所有的新文件和文件夹都会创建UID和GID。事实上如果
<src>
是一个远程文件URL,那么目标文件的权限将会是600
- VOLUME:创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等
- EXPOSE:指定在docker允许时指定的端口进行转发
- CMD:启动容器时执行的命令
- Dockerfile中只能有一个CMD指令。如果你指定了多个,那么只有最后个CMD指令是生效的
- 可以被
docker run $image $other_command
中的$other_command
覆盖
- ONBUILD:让指令延迟執行
- 延迟到下一个使用
FROM
的Dockerfile在建立image时执行,只限延迟一次
- 延迟到下一个使用
- ARG:定义仅在建立image时有效的变量
- ENTRYPOINT:指定Docker image运行成instance(也就是 Docker container)时,要执行的命令或者文件
- 默认的
ENTRYPOINT
是/bin/sh -c
,但是没有默认的CMD
- 当执行
docker run -i -t ubuntu bash
,默认的ENTRYPOINT
就是/bin/sh -c
,且CMD
就是bash
CMD
本质上就是ENTRYPOINT
的参数
- 默认的
1 | # Use an official Python runtime as a parent image |
requirements.txt(上面的Dockerfile中的Run命令用到了这个文件)
1 | Flask |
1 | from flask import Flask |
创建镜像:docker build -t friendlyhello .
运行应用:docker run -p 4000:80 friendlyhello
5 docker命令行工具
学会利用--help
参数
1 | docker --help # 查询所有顶层的参数 |
6 基础镜像
6.1 Alpine
Alpine Linux是一个轻型Linux发行版,它不同于通常的Linux发行版,Alpine采用了musl libc 和 BusyBox以减少系统的体积和运行时的资源消耗。Alpine Linux提供了自己的包管理工具:apk
构建一个带有bash的docker镜像
1 | FROM alpine:3.10.2 |
6.2 Jib
1 | <plugin> |
7 Docker Compose
7.1 Install
1 | sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose |
7.2 Usage
docker-compose [ -f xxx.yml ] up
docker-compose [ -f xxx.yml ] up -d
docker-compose [ -f xxx.yml ] down
docker-compose [ -f xxx.yml ] start
docker-compose [ -f xxx.yml ] stop
docker-compose [ -f xxx.yml ] restart
docker-compose [ -f xxx.yml ] rm
docker-compose [ -f xxx.yml ] ps
docker-compose [ -f xxx.yml ] ls
8 Tips
- 启动并保持容器运行
- 可以执行一个不会终止的程序:
docker run -dit xxx:v1
- 启动的同时,开启一个bash:
docker run -it 9a88e0029e3b /bin/bash
- 可以执行一个不会终止的程序:
- 在主机与Docker容器之间拷贝文件
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
- 打开
D-Bus connection
docker run -d -e "container=docker" --privileged=true [ID] /usr/sbin/init
- 容器启动的
CMD
包含/usr/sbin/init
即可
- 启停容器:
docker start <container-id>
docker stop <container-id>
- 在指定容器中执行命令
docker exec -ti my_container /bin/bash -c "echo a && echo b"
- 查看docker container对应的pid
docker inspect <container-id> | grep Pid
- 删除某个tag
docker rmi <repository>:<tag>
,不要用镜像id
- 列出所有的镜像id
docker images -q
- 将镜像打包成文件,从文件中导入镜像
docker save -o alpine.tar alpine:3.10.2
docker load < alpine.tar
- 设置时区
docker run -e TZ=Asia/Shanghai ...
- 设置内核参数(需要使用特权模式)
- 编写DockerFile的时候,把修改的内核参数写到CMD中(不能在制作DockerFile的时候通过RUN进行修改,因为这些内核文件是只读的)
- 启动的时候指定特权模式:
docker run --privileged
- 在容器中使用docker命令
--privileged
:使用特权模式-v /var/run/docker.sock:/var/run/docker.sock
:将docker socket文件挂载到容器-v $(which docker):/bin/docker
:将docker命令挂载到容器
- 启动容器时,加入网络命名空间
docker run [--pid string] [--userns string] [--uts string] [--network string] <other options>
docker run -d --net=container:<已有容器id> <镜像id>
- 删除docker命令后,docker的工作目录仍然是保留的(包含了镜像)若要彻底删除,可以通过如下命令
rm -rf /var/lib/docker
- 查看img的构建记录:
docker history <img>
- 查看img的详情:
docker inspect <img>
- 查看容器资源占用情况:
docker stats <container>
- 清理无用镜像:
docker system prune -a
- 让普通用户有权限使用
docker
:sudo usermod -aG docker username
8.1 修改存储路径
默认情况下,docker相关的数据会存储在/var/lib/docker
。编辑配置文件/etc/docker/daemon.json
(没有就新建),增加如下配置项:
1 | { |
然后通过systemctl restart docker
重启docker即可
8.2 修改镜像源
编辑配置文件/etc/docker/daemon.json
(没有就新建),增加如下配置项:
1 | { |
然后通过systemctl restart docker
重启docker即可
8.3 跨平台运行容器
默认情况下,docker是不支持--platform
参数的,可以通过修改/etc/docker/daemon.json
,添加如下配置项后,重启docker,开启该功能
1 | { |
如果我们在x86的平台上运行arm64的docker镜像,会得到如下错误信息
1 | docker run --platform linux/arm64 --rm arm64v8/ubuntu:18.04 uname -a |
此时,我们可以借助跨平台工具qemu
,下载地址。该方法对内核版本有要求,貌似要4.x以上,我的测试环境的内核版本是4.14.134
1 | # 下载qemu-aarch64-static |
docker run --rm --privileged multiarch/qemu-user-static:register
是向内核注册了各异构平台的binfmt handler
,包括aarch64
等等,这些注册信息就包括了binfmt handler
的路径,比如/usr/bin/qemu-aarch64-static
等等,注册信息都在/proc/sys/fs/binfmt_misc
目录下,每个注册项都是该目录下的一个文件。实际的qemu-xxx-static
文件还得手动放置到对应目录中才能生效
8.4 镜像裁剪工具-dockerslim
1 | docker-slim build --http-probe=false centos:7.6.1810 |
裁剪之后,镜像的体积从202MB
变为3.55MB
。但是裁剪之后,大部分的命令都被裁剪了(包括ls
这种最基础的命令)
8.5 如何感知程序是否运行在容器中
一般来说,如果运行环境是容器,那么会存在/.dockerenv
这个文件
8.6 从容器构建镜像
保留镜像原本的layer,每次commit都会生成一个layer,这样会导致镜像越来越大:
1 | docker commit <container-id> <new_image> |
将容器导出成单层的镜像:
1 | docker export <container-id> -o centos7.9.2009-my.tar |
8.7 Setup Http Proxy
Add file /etc/systemd/system/docker.service.d/http-proxy.conf
with following content:
1 | [Service] |
Check and restart
1 | systemctl daemon-reload |
9 FAQ
9.1 k8s环境docker异常
在k8s环境中,若容器运行时用的是docker
,那么该docker
会依赖containerd
,当containerd
不正常的时候,docker
也就不正常了。恢复containerd
的办法:将/var/lib/containerd/io.containerd.metadata.v1.bolt
这个文件删掉
9.2 read unix @->/var/run/docker.sock: read: connection reset by peer
- 没有权限
- 多套
docker
共用了同一个/var/run/docker.sock
套接字文件,可以用lsof -U | grep docker.sock
查看。默认情况下只有2个记录,一个是systemd
的,另一个是dockerd
的
10 参考
- Docker Hub
- Docker历史版本下载
- Docker
- Docker Command
- Docker 教程
- Docker 原理篇
- 深入分析Docker镜像原理
- Docker之Dockerfile语法详解
- docker容器与虚拟机有什么区别?
- docker与虚拟机性能比较
- RunC 简介
- Containerd 简介
- 从 docker 到 runC
- jib
- 探讨Docker容器中修改系统变量的方法
- What is the difference between CMD and ENTRYPOINT in a Dockerfile?
- Sharing Network Namespaces in Docker
- x86机器上运行arm64 docker
- github-qemu
- 跨平台构建 Docker 镜像
- 跨平台构建 Docker 镜像新姿势,x86、arm 一把梭
- QEMU和KVM的关系
- dockerslim
- 第三章 Docker容器的生命周期