1 概览
1.1 架构
Docker提供了一个开发、打包、运行的APP平台,把APP和底层的基础架构隔离开。
Docker Engine是一个后台进程,提供了Rest API的Server和CLI接口。
1.2 底层技术支持
Namespaces:隔离用户空间、网络空间、进程(pid、net、ipc、mnt、uts)
Control groups:做资源限制
Union file systems:Container和Image的分层
2 Image
2.1 Image的概念
Image是文件和meta data的集合,Image是分层的,每一层都可以添加、修改、删除文件,成为一个新的image,不同的image可以共享相同的layer,Image本身是只读的。
2.2 获取Image
可以在Docker Hub获取官方提供的Image
docker pull + image name
例如:docker pull hello-world
[root@localhost ~]# docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
b8dfde127a29: Pull complete
Digest: sha256:308866a43596e83578c7dfa15e27a73011bdd402185a84c5cd7f32a88b501a24
Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest
[root@localhost ~]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d1165f221234 3 weeks ago 13.3kB
2.3 自定义Base Image
编译得到可执行C程序:gcc -static hello.c -o hello
创建Dockerfile
FROM scratch
ADD hello /
CMD ["/hello"]
执行命令:docker build -t xd1998/hello-docker .
("."表示当前目录找docker文件)
执行Dockerfile中指定的三个步骤
Sending build context to Docker daemon 368.8MB
Step 1/3 : FROM scratch
--->
Step 2/3 : ADD hello /
---> d9b08486b846
Step 3/3 : CMD ["/hello"]
---> Running in 74e47a7e6df1
Removing intermediate container 74e47a7e6df1
---> 6f933eff0af6
Successfully built 6f933eff0af6
Successfully tagged xd1998/hello-docker:latest
查看镜像:docker image ls
[root@localhost ~]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
xd1998/hello-docker latest 6f933eff0af6 2 minutes ago 865kB
hello-world latest d1165f221234 3 weeks ago 13.3kB
查看Image历史:docker history 6f933eff0af6
[root@localhost ~]# docker history 6f933eff0af6
IMAGE CREATED CREATED BY SIZE COMMENT
6f933eff0af6 5 minutes ago /bin/sh -c #(nop) CMD ["/hello"] 0B
d9b08486b846 5 minutes ago /bin/sh -c #(nop) ADD file:c6c2ab724dad6ae96… 865kB
运行镜像:docker run xd1998/hello-docker
得到打印的结果,说明创建的Base Image可以作为一个Container去执行
[root@localhost ~]# docker run xd1998/hello-docker
hello docker!
3 Container
3.1 Container的概念
Container是通过Image创建的,是在Image layer之上简历一个可读写的Container layer。Container和Image的关系类似于面向对象中实例和类的关系。Image负责应用的存储和分发,Container负责运行应用。
3.2 相关操作
查看正在运行的容器:docker container ls
查看所有容器:docker container ls -a
[root@localhost ~]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6e2d332e348f xd1998/hello-docke "/hello" 17 minutes ago Exited (14) 17 minutes ago bold_albattani
80850a9eb600 hello-world "/hello" About an hour ago Exited (0) About an hour ago wonderful_pasteur
在运行一个容器的时候,默认会执行CMD中定义的命令,因为自定义的CMD中不是一个常驻内存的命令,所以执行完命令后容器的状态就变为了Exited
交互式运行容器:docker run -it imageName
删除容器:docker container rm containerID
删除镜像:docker image rm imageID
打印输出所有容器的ID:docker container ls -aq
清理所有容器:docker rm $(docker container ls -aq)
清除状态为exited的容器:docker container ls -f "status=exited" -q
4 Dockerfile语法与最佳实践
4.1 FROM
最佳实践:使用官方的image作为base image
FROM scratch # 制作base image
FROM centos # 使用base image
FROM ubuntu:14.04
4.2 LABEL
最佳实践:应该写明metadata
LABEL maintainer="xxx@163.com"
LABEL version="1.0"
LABEL description="this is description"
4.3 RUN
最佳实践:每执行依次RUN得到新的一层,所以最好合并多条命令为一行,为了命令的易读性,可以使用反斜线换行。
RUN yum update && yum install -y vim \
python-dev
4.4 WORKDIR
最佳实践:WORKDIR可以设定当前工作目录,使用WORKDIR,不要用RUN cd,尽量使用绝对目录。
WORKDIR /test # 创建test目录
WORKDIR demo
RUN pwd # 输出/test/demo
4.5 ADD/COPY
最佳实践:COPY优先于ADD,ADD除了可以添加文件到指定目录,还可以解压缩。添加远程文件/目录使用curl或者wget
ADD hello /
ADD test.tar.gz / # 解压缩到根目录
WORKDIR /root
ADD hello test/ # 将hello添加到/root/test
WORKDIR /root
COPY hello test/ # 将hello添加到/root/test
4.6 ENV
最佳实践:最好使用ENV定义常量
ENV MYSQL_VERSION 5.6 # 设置常量
RUN apt-get install -y mysql-server="${MYSQL_VERSION}" \
&& rm -rf /var/lib/apt/lists/* # 可以用${MYSQL_VERSION}使用常量4,
4.7 VOLUME / EXPOSE
VOLUME仅支持指定容器的挂载点目录,不支持宿主机的挂载点目录。如果挂载点目录路径下之前后文件存在,docker run命令会在卷挂在完成之后将所有文件实现复制共享。
EXPOSE可以指定镜像暴露的端口,在启动后去动态绑定至宿主机的随机端口和所有地址。
4.8 CMD / ENTRYPOINT
RUN是执行命令并创建一个新的Image Layer,CMD是设置容器启动后默认执行的命令和参数,ENTRYPOINT是设置容器启动时运行的命令。
Shell格式和Exec格式的区别:shell可以识别ENV变量,exec不能识别ENV变量,需要指明通过shell执行:ENTRYPOINT ["/bin/bash", "-c", "echo hello $name"]。
# shell格式
RUN apt-get install -y vim
CMD echo "hello docker"
ENRTYPOINT echo "hello docker"
# exec格式
RUN ["apt-get", "install", "-y", "vim"]
CMD ["/bin/echo", "hello docker"]
ENTRYPOINT ["/bin/echo", "hello docker"]
CMD是容器启动时默认执行的命令,如果docker run指定了其他命令,CMD命令会被忽略,如果定义了多个CMD,只有最后一个CMD会被执行。
ENTRYPOINT让容器以应用程序或服务的形式运行,不会被忽略,一定被执行
最佳实践:写一个shell脚本作为ENTRYPOINT
COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 27017
CMD ["mongod"]
4.9 发布自己的镜像
登录:docker login
推送:docker push tag:latest
5 Dockfile实践
创建/hello-docker/app.py:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "hello docker"
if __name__ == '__main__':
app.run()
创建/hello-docker/Dockerfile:
FROM python:2.7
LABEL "maintainer=XD1998<xxx@163.com>"
RUN pip install flask
COPY app.py /app
WORKDIR /app
EXPOSE 5000
CMD ["python", "app.py"]
执行build命令:docker build -t xd1998/hello-docker .