1.1 Docker 镜像操作
1.1.1 查看本地镜像
docker images
1.1.2 导出镜像
docker save -o <存储名称> REPOSITORY:TAG
1.1.3 删除镜像
docker rmi REPOSITORY:TAG
1.1.4 导入镜像
docker load -i <存储名称>
1.2. Docker 容器操作
1.2.1 创建容器
docker create nginx:1.9.0
docker ps -a
1.2.2 启动容器
docker start
1.2.3 停止容器
docker stop
1.2.4 重启容器
docker restart
1.2.5 查看容器
docker ps
常用选项:
-a:列出所有容器(包括未运行的容器),默认情况下只列出正在运行的容器
-l:列出最后一个创建的容器
-q:仅列出容器 ID
-n:列出最后 X 个创建的容器
1.2.6 运行容器
docker run
语法:docker run [OPTIONS] IMAGE [COMMAND] [ARG…]
常用选项:
-t, --tty:分配伪 TTY,常与-i 一起使用
-i, --interactive:进入交互模式
docker run -ti nginx bash
-d, --detach:后台模式运行容器,并打印容器 ID
- –name string:设置容器的名称,如果没有就随机生成一个
docker run -d --name=nginx nginx tail -f /etc/hosts
-m, --memory:指定内存配额,单位 b,k,m,g
docker run -d --memory=100MB nginx
–rm:容器退出时,自动删除容器,不需要在去执行删除容器操作
与-d 选项 冲突不可同时使用
-p, --publish list:手动指定映射对外提供服务的端口,格式为
<host_port : container_port>
docker run -d -p 8090:80 nginx
–network 容器使用的网络,以常用的 host 模式和 bridge 模式为例:
前面片子中提过host模式下,容器不会获得一个独立的Network Namespaces, 而是和宿主机共用一个 Network Namespaces。容器将复用宿主机的 IP 地址及端 口、主机名、路由表、防火墙规则等。但是容器的其它方面,如进程、文件系统 等还是和宿主机隔离。
bridge 是 docker 默认网络设置,此模式会为每一个容器分配 Network Namespaces,设置独立的 hostname、IP 地址、路由表、防火墙规则等,并将容器连接到 Linux 虚拟网桥上。
-e, --env list:设置环境变量
1.2.7 查看容器日志
docker logs 容器 ID
1.2.8 查看容器详细信息
docker inspect
docker inspect -f=‘{{.State.Status}}’ 37dc(容器 ID)
docker inspect f6b3780c83fe
1.3 镜像仓库操作
1.3.1 配置私有镜像仓库
在使用 http 协议的私有镜像仓库时需要在 docker 进程的启动参数或者在 配置文件中配置–insecure-registries 参数:(root 权限查看)
地址可以为 IP 或域名,配置后重启 docker daemon,参数生效
1.3.2 登录私有镜像仓库
1.3.3 下载镜像并修改私有镜像标签
docker pull
docker tag
1.3.4上传镜像到私有镜像仓库
docker push
1.3.5 登出私有镜像仓库
1.3.6 镜像名命名规则
示例:10.0.0.11:10000/majd/httpd:v1.0
➢ 镜像仓库地址:10.0.0.11
➢ 镜像项目名:majd
➢ 应用名称: httpd
➢ 镜像 TAG:v1.0
1.4 Dockerfile 定制镜像
Dockerfile 是一个文本文件,其内包含了一条条的指令,每一条指令构建 一层镜像,因此每一条指令的内容,就是描述该层应当如何构建。在一个空白目录中,建立一个文本文件,并命名为 Dockerfile
Dockerfile 的指令是忽略大小写的,建议使用大写,使用 # 作为注释。
常用构建指令:
FROM:
所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。
FROM 就是指定用于构建新镜像的基础镜像
·如果本地没有该基础镜像,则会自动从 Docker Hub 拉取该基础镜像。
·FROM 必须是 Dockerfile 中非注释行的第一个指令,即一个 Dockerfile 从 FROM 语句开始。
MAINTAINER:
声明作者
RUN:
RUN 指令是用来执行命令行命令的,用于创建镜像
语法格式 1:RUN
语法格式 2:RUN [“executable”, “param1”, “param2”]
·格式 1 将在 shell 终端中执行命令。
· 格式 2 这更像是函数调用中的格式。
· RUN 会将当前镜像运行于一个新的临时容器中,并在此基础上执行指定命 令,然后把执行后的更改,提交为新的镜像。后续的 RUN 都以之前 RUN 提交后的 镜像为基础。
·RUN 产生的缓存在下一次构建的时候会被重用,可以使用–no-cache 选项 禁用缓存。
示例:
FROM centos:7.2.1511
RUN mkdir /test001/
执行 build 命令,生成镜像 docker build -t test001:v1 .
docker run -ti test001:v1 bash
进入容器后执行
ENTRYPOINT:
指定容器启动时执行的命令
语法格式 1:ENTRYPOINT [“executable”, “param1”, “param2”] 1213
语法格式 2:ENTRYPOINT command param1 param2
·一个 Dockerfile 只能有一条 ENTRYPOINT 命令,多条则只执行最后一条 ENTRYPOINT 命令
·需要通过 docker run 的参数 --entrypoint 来 指 定 才 能 替 代 ENTRYPOINT,否则不会覆盖掉 ENTRYPOINT 指定的命令。
CMD:
指定容器启动时执行的命令
语法格式 1:CMD [“executable”,“param1”,“param2”]使用 exec 执行,推 荐方式;
语法格式 2:CMD command param1 param2 在 shell 中执行;
语法格式 3:CMD [“param1”,“param2”] 提供给 ENTRYPOINT 的默认参数。
·一个 Dockerfile 只能有一条 CMD 命令,多条则只执行最后一条 CMD 命令
· 当用户启动容器时指定了命令,则会覆盖掉 CMD 指定的命令。
示例 1:
vi Dockerfile
FROM centos
RUN mkdir /test001/
ENTRYPOINT [“cat”, “/etc/hosts”]
保存退出
执行 build 命令,生成镜像 docker build -t centos:v2 .
docker run cetos:v2
docker run centos:v2 echo hello
docker run --entrypoint=echo centos:v2 hello
示例 2:
vi Dockerfile
FROM centos
RUN mkdir /test001/
CMD [“cat”, “/etc/hosts”]
保存退出
执行 build 命令,生成镜像 docker build -t centos:v3 .
docker run centos:v3
docker run centos:v3 echo hello
EXPOSE:
EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 。语法格式:EXPOSE […]
EXPOSE 的端口示例:
vi Dockerfile
FROM centos
RUN mkdir /test001/
EXPOSE 4097
CMD [“cat”, “/etc/hosts”]
保存退出
执行 build 命令,生成镜像 docker build -t centos:v1 .
docker run -d -P centos:v1 tail -f /etc/hosts
docker ps
要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。 -p ,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射
WORKDIR:
为后续 RUN/CMD/ENTRYPOINT 指定命令执行的当前目录。
示例:
vi Dockerfile
FROM centos
RUN mkdir /test001/
RUN cd /test001/
RUN echo “hello” > test.txt
CMD [“cat”, “/etc/hosts”]
保存退出
执行 build 命令,生成镜像 docker build -t centos:v5 .
docker run -ti centos:v5 bash
在容器内:执行 ls /test001/
示例 2:
FROM centos
RUN mkdir /test001/
WORKDIR /test001/
RUN echo “hello” > test.txt
CMD [“cat”, “/etc/hosts”]
保存退出
执行 build 命令,生成镜像 docker build -t centos:v6 .
docker run -ti centos:v6 bash
在容器内:执行 ls
每一个 RUN 都是启动一个容器、执行命令、然后提交存储层文件变更。第一层 RUN cd /test001 的执行仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化。因此如果需要改变以后各层的工作目录的位置,那么应该使用 WORKDIR 指令。
COPY:
复制本地主机的文件或目录到容器中指定的路径
语法格式:COPY
USER:
指定运行容器中的服务所使用的用户名或 UID
语法格式:USER <用户名或 UID>
ENV:
设置环境变量
语法格式: ENV
1.5 容器网络
1.5.1 Bridge 网络
步骤 1 创建一个名为 net1 的 Bridge 网络。
docker network create --driver bridge net1
步骤 2 查看 net1 网桥,已自动配置subnet和gateway
docker network inspect net1
步骤三 创建第二个网桥,指定IP网段,命名伟net2
docker network create --driver bridge --subnet 172.10.10.0/24 --gateway 172.10.10.1 net2
步骤四 启动三个centos容器,分别命名为cetnos1,centos2,centos3.其中centos1加入net1,centos2加入net2,centos3加入net2并配置静态ip。
docker run --name cetnos1 -dit --network=net1 centos
docker run --name cetnos2 -dit --network=net2 centos
docker run --name cetnos3 -dit --network=net2 --ip 172.10.10.10 centos
步骤五 分别查看三个容器的ip,发现centos1和centos2,centos3位于不同网段,centos2和centos3位于同一网段且不同ip
docker inspect centos1
docker inspect centos2
docker inspect centos3
步骤六 进入centos3,验证网络联通性。Centos3与centos2可以通信,与centso1不通
docker exec -it centos3 /bin/bash
步骤七 为centos1添加一块网卡,并加入net2网络,进入centos1并验证网络连通性
docker network connect net2 centos1
1.6容器持久化存储
Docker容器中持久化数据一般采用两种存储方式:
Volume
Bind-mount
无论是volume还是bind-mount其本质上是宿主机文件系统上的目录或文件
无论是volume还是bind-mount其上存放的数据生命周期独立于容器,即容器删除后,volume和bind-mount上的数据依旧存在。
1.6.1 volume
Vomule完全又docker管理,使用卷时,不需要指定mount源,它会在主机的docker存储目录中自动创建一个新目录,docker会管理该目录的内容。
Volume常用命令:
docker volume create 创建卷
docker volume ls 查看卷信息
docker volume rm 删除卷
步骤一 创建一个卷,并挂载一个httpd容器
docker run -d -p 8080:80 -v /usr/local/apache2/htdocs httpd
步骤二 查看volume信息
Docker volume ls
步骤三 查看容器的volume挂载信息,同时得到volume的路径,Type=volume
docker inspect 4f6
步骤四 查看volume中的数据
cd …
发现和容器内/usr/local/apache2/htdocs的数据一致
步骤五 进入容器修改index.hrml文件的内容为 this majd server
docker exec -it 4f6c bash
echo “this is majd server”
步骤六 再次查看volume中的数据,已同步跟新,实现容器与主机数据共享
步骤七 强制删除httpd容器,发现主句volume数据依然存在,实现持久化
docker rm -f 4f6c
1.6.2 bind mount
Bind mount是将宿主机上已有的文件或目录挂载到容器中
若将bind mount绑定到容器的某个非空目录下,则会隐藏容器目录下现有的内容。若不希望覆盖整个目录,可单独挂载某个文件。还可通过ro参数将容器对数据的权限设置为只读(容器只读,宿主机仍可修改)。
步骤一 在宿主机上创建/root/htdocs目录,以只读的方式挂载给名为httpd1的httpd容器,映射端口为8081
mkdir /root/htdocs
docker run -d --name httpd1 -p 8081:80 -v /root/htdocs:/usr/local/apache2/htdocs:ro httpd
步骤二 查看容器挂载信息 Type=bind
docker inspect httpd1
步骤三 在宿主机上更新index.html文件数据,发现容器内的文件数据也一起更新
cd /root/htdocs/
echo ‘This is test server’ > index.html
docker exec -it httpd1 /bin/bash
cat index.html
步骤四 进入httpd1容器中更新index.html文件内容发现提示read-only file system
docker exec -it httpd1 /bin/bash
步骤五 将宿主机/root/htdocs挂载到名为httpd2的httpd容器,端口为8082,不设置ro
docker run -d --name httpd2 -p 8082:80 -v /root/htdocs:/usr/lcoal/apache2/htdocs httpd
步骤六 进入httpd2容器更改index.html文件,发现可以更改文件数据。
docker exec -it httpd2 /bin/bash
echo ‘123’ > htdocs/index.html
而且主机、httpd1、httpd2数据一致,实现了容器间的数据共享
1.6.3 volume container
步骤一 创建一个名为myvolume1的空卷并查看
docker volume create myvolume1
docker volume ls
步骤二 将myvolume1挂载到一个名为vc的容器
docker create --name vc -v myvolume1:/usr/local/apache2/htdocs httpd
步骤三 运行两个httpd容器,分别命名为httpd3.httpd4。并且都引用容器vc中的数据
docker run --name httpd3 -d -p 8083:80 --volumes-from vc httpd
docker run --name httpd4 -d -p 8084:80 --volumes-from vc httpd
步骤四 进入httpd3容器中更新index.html文件数据,进入httpd4容器发现数据已同步更新
1.7 底层实现技术: namespace和cgroup 资源限制
1.7.1 namespace
步骤一 运行一个centos容器,并设置容器的hostname=majdhost
步骤二 在容器中添加一个用户majdtest1
步骤三 打开另一个宿主机终端,查看hostname和用户majdtest3
宿主机的hosntname不是容器中设置的majdhost,也没有用户majdtest1,因此证明容器进程的user空间hostname空间分别由user namespaces和UTS namespace隔离,独立于宿主机。
步骤四 在容器内查看PID,/bin/bash的PID为1
步骤五 在宿主机查看改容器的PID,/bin/bash的PID为11958
ps axf
通过以上可知,容器进程的PID空间由PID namespace 空间隔离,独立于宿主机
1.7.2 CPU限制
步骤一 启动一个名为majdtest1的压力测试容器(progrium/stress),cpu权重设置为512
docker run --name majdtest1 -it --cpu-shares 512 progrium/stress --cpu 2
步骤二 打开第二个宿主机终端,top查看cpu使用率,已将近100%
步骤三 打开第三个宿主机终端,启动第二个压力测试容器majdtest2权重为2048
docker run --name majdtest2 -it --cpu-shares 2048 progrium/stress --cpu 2
步骤四 再次查看cpu使用率,majdtest2的cpu占用是majdtest1的4倍
步骤五 查看container ID
docker ps
步骤六 根据container ID,查找cgroup下相应的cpu配置文件,以majdtest1为例
cpu.shares 的值为之前启动时设置的权重512
1.7.3 内存资源限制
步骤一 在后台启动一个centos容器,并限制其最多使用400M内存和100Mswap。
docker run -m 400M --memory-swap=500M -dit centos /bin/bash
步骤二 找到该容器在cgroup下的内存配置目录,查看内存配置文件发现内存使用限制为400M,内存和swap限制为500M
通过查看配置文件发现内存限制为419430400b=400M,swap和内存共524288000b=500M