1.1 Docker 镜像操作

1.1.1 查看本地镜像

docker images

容器 镜像 容器 镜像预热_容器 镜像

1.1.2 导出镜像

docker save -o <存储名称> REPOSITORY:TAG

容器 镜像 容器 镜像预热_容器 镜像_02

1.1.3 删除镜像

docker rmi REPOSITORY:TAG

容器 镜像 容器 镜像预热_docker_03

1.1.4 导入镜像

docker load -i <存储名称>

容器 镜像 容器 镜像预热_docker_04

1.2. Docker 容器操作

1.2.1 创建容器

docker create nginx:1.9.0

docker ps -a

容器 镜像 容器 镜像预热_运维_05

1.2.2 启动容器

docker start

容器 镜像 容器 镜像预热_运维_06

1.2.3 停止容器

docker stop

容器 镜像 容器 镜像预热_云计算_07

1.2.4 重启容器

docker restart

容器 镜像 容器 镜像预热_运维_08

1.2.5 查看容器

docker ps

常用选项:

-a:列出所有容器(包括未运行的容器),默认情况下只列出正在运行的容器

-l:列出最后一个创建的容器

-q:仅列出容器 ID

-n:列出最后 X 个创建的容器

容器 镜像 容器 镜像预热_运维_09

1.2.6 运行容器

docker run

语法:docker run [OPTIONS] IMAGE [COMMAND] [ARG…]

常用选项:

-t, --tty:分配伪 TTY,常与-i 一起使用

-i, --interactive:进入交互模式

docker run -ti nginx bash

容器 镜像 容器 镜像预热_云计算_10


-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

容器 镜像 容器 镜像预热_运维_11


–network 容器使用的网络,以常用的 host 模式和 bridge 模式为例:

前面片子中提过host模式下,容器不会获得一个独立的Network Namespaces, 而是和宿主机共用一个 Network Namespaces。容器将复用宿主机的 IP 地址及端 口、主机名、路由表、防火墙规则等。但是容器的其它方面,如进程、文件系统 等还是和宿主机隔离。

bridge 是 docker 默认网络设置,此模式会为每一个容器分配 Network Namespaces,设置独立的 hostname、IP 地址、路由表、防火墙规则等,并将容器连接到 Linux 虚拟网桥上。

-e, --env list:设置环境变量

容器 镜像 容器 镜像预热_centos_12

1.2.7 查看容器日志

docker logs 容器 ID

容器 镜像 容器 镜像预热_docker_13

1.2.8 查看容器详细信息

docker inspect
docker inspect -f=’{{.State.Status}}’ 37dc(容器 ID)
docker inspect f6b3780c83fe

容器 镜像 容器 镜像预热_容器 镜像_14


容器 镜像 容器 镜像预热_centos_15

1.3 镜像仓库操作

1.3.1 配置私有镜像仓库

在使用 http 协议的私有镜像仓库时需要在 docker 进程的启动参数或者在 配置文件中配置–insecure-registries 参数:(root 权限查看)

容器 镜像 容器 镜像预热_docker_16


容器 镜像 容器 镜像预热_运维_17


地址可以为 IP 或域名,配置后重启 docker daemon,参数生效

1.3.2 登录私有镜像仓库

容器 镜像 容器 镜像预热_docker_18

1.3.3 下载镜像并修改私有镜像标签

docker pull

docker tag

容器 镜像 容器 镜像预热_centos_19

1.3.4上传镜像到私有镜像仓库

docker push

容器 镜像 容器 镜像预热_运维_20

1.3.5 登出私有镜像仓库

容器 镜像 容器 镜像预热_容器 镜像_21

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”]

保存退出

容器 镜像 容器 镜像预热_docker_22


执行 build 命令,生成镜像 docker build -t centos:v1 .

docker run -d -P centos:v1 tail -f /etc/hosts

docker ps

容器 镜像 容器 镜像预热_centos_23


要将 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

容器 镜像 容器 镜像预热_云计算_24


步骤 2 查看 net1 网桥,已自动配置subnet和gateway

docker network inspect net1

容器 镜像 容器 镜像预热_docker_25


步骤三 创建第二个网桥,指定IP网段,命名伟net2

docker network create --driver bridge --subnet 172.10.10.0/24 --gateway 172.10.10.1 net2

容器 镜像 容器 镜像预热_centos_26


步骤四 启动三个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

容器 镜像 容器 镜像预热_容器 镜像_27


步骤五 分别查看三个容器的ip,发现centos1和centos2,centos3位于不同网段,centos2和centos3位于同一网段且不同ip

docker inspect centos1

容器 镜像 容器 镜像预热_centos_28


docker inspect centos2

容器 镜像 容器 镜像预热_运维_29


docker inspect centos3

容器 镜像 容器 镜像预热_容器 镜像_30


步骤六 进入centos3,验证网络联通性。Centos3与centos2可以通信,与centso1不通

docker exec -it centos3 /bin/bash

容器 镜像 容器 镜像预热_docker_31


步骤七 为centos1添加一块网卡,并加入net2网络,进入centos1并验证网络连通性

docker network connect net2 centos1

容器 镜像 容器 镜像预热_centos_32

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

容器 镜像 容器 镜像预热_centos_33


步骤二 查看volume信息

Docker volume ls

容器 镜像 容器 镜像预热_云计算_34


步骤三 查看容器的volume挂载信息,同时得到volume的路径,Type=volume

docker inspect 4f6

容器 镜像 容器 镜像预热_docker_35


步骤四 查看volume中的数据

cd …

容器 镜像 容器 镜像预热_云计算_36


发现和容器内/usr/local/apache2/htdocs的数据一致

步骤五 进入容器修改index.hrml文件的内容为 this majd server

docker exec -it 4f6c bash

echo “this is majd server”

容器 镜像 容器 镜像预热_容器 镜像_37


步骤六 再次查看volume中的数据,已同步跟新,实现容器与主机数据共享

容器 镜像 容器 镜像预热_centos_38


步骤七 强制删除httpd容器,发现主句volume数据依然存在,实现持久化

docker rm -f 4f6c

容器 镜像 容器 镜像预热_云计算_39

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

容器 镜像 容器 镜像预热_docker_40

步骤二 查看容器挂载信息 Type=bind

docker inspect httpd1

容器 镜像 容器 镜像预热_容器 镜像_41

步骤三 在宿主机上更新index.html文件数据,发现容器内的文件数据也一起更新

cd /root/htdocs/

echo ‘This is test server’ > index.html

docker exec -it httpd1 /bin/bash

cat index.html

容器 镜像 容器 镜像预热_云计算_42

步骤四 进入httpd1容器中更新index.html文件内容发现提示read-only file system

docker exec -it httpd1 /bin/bash

容器 镜像 容器 镜像预热_docker_43

步骤五 将宿主机/root/htdocs挂载到名为httpd2的httpd容器,端口为8082,不设置ro

docker run -d --name httpd2 -p 8082:80 -v /root/htdocs:/usr/lcoal/apache2/htdocs httpd

容器 镜像 容器 镜像预热_容器 镜像_44

步骤六 进入httpd2容器更改index.html文件,发现可以更改文件数据。

docker exec -it httpd2 /bin/bash

echo ‘123’ > htdocs/index.html

容器 镜像 容器 镜像预热_docker_45

而且主机、httpd1、httpd2数据一致,实现了容器间的数据共享

容器 镜像 容器 镜像预热_centos_46

1.6.3 volume container

步骤一 创建一个名为myvolume1的空卷并查看

docker volume create myvolume1

docker volume ls

容器 镜像 容器 镜像预热_运维_47

步骤二 将myvolume1挂载到一个名为vc的容器

docker create --name vc -v myvolume1:/usr/local/apache2/htdocs httpd

容器 镜像 容器 镜像预热_centos_48

步骤三 运行两个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

容器 镜像 容器 镜像预热_云计算_49

步骤四 进入httpd3容器中更新index.html文件数据,进入httpd4容器发现数据已同步更新

容器 镜像 容器 镜像预热_容器 镜像_50


容器 镜像 容器 镜像预热_运维_51

1.7 底层实现技术: namespace和cgroup 资源限制

1.7.1 namespace

步骤一 运行一个centos容器,并设置容器的hostname=majdhost

容器 镜像 容器 镜像预热_运维_52


步骤二 在容器中添加一个用户majdtest1

容器 镜像 容器 镜像预热_容器 镜像_53


步骤三 打开另一个宿主机终端,查看hostname和用户majdtest3

容器 镜像 容器 镜像预热_centos_54


宿主机的hosntname不是容器中设置的majdhost,也没有用户majdtest1,因此证明容器进程的user空间hostname空间分别由user namespaces和UTS namespace隔离,独立于宿主机。步骤四 在容器内查看PID,/bin/bash的PID为1

容器 镜像 容器 镜像预热_运维_55


步骤五 在宿主机查看改容器的PID,/bin/bash的PID为11958

ps axf

容器 镜像 容器 镜像预热_centos_56


通过以上可知,容器进程的PID空间由PID namespace 空间隔离,独立于宿主机

1.7.2 CPU限制

步骤一 启动一个名为majdtest1的压力测试容器(progrium/stress),cpu权重设置为512

docker run --name majdtest1 -it --cpu-shares 512 progrium/stress --cpu 2

容器 镜像 容器 镜像预热_云计算_57


步骤二 打开第二个宿主机终端,top查看cpu使用率,已将近100%

容器 镜像 容器 镜像预热_centos_58


步骤三 打开第三个宿主机终端,启动第二个压力测试容器majdtest2权重为2048

docker run --name majdtest2 -it --cpu-shares 2048 progrium/stress --cpu 2

容器 镜像 容器 镜像预热_容器 镜像_59


步骤四 再次查看cpu使用率,majdtest2的cpu占用是majdtest1的4倍

容器 镜像 容器 镜像预热_运维_60


步骤五 查看container ID

docker ps

容器 镜像 容器 镜像预热_docker_61


步骤六 根据container ID,查找cgroup下相应的cpu配置文件,以majdtest1为例

容器 镜像 容器 镜像预热_容器 镜像_62


cpu.shares 的值为之前启动时设置的权重512

1.7.3 内存资源限制

步骤一 在后台启动一个centos容器,并限制其最多使用400M内存和100Mswap。

docker run -m 400M --memory-swap=500M -dit centos /bin/bash

容器 镜像 容器 镜像预热_centos_63


步骤二 找到该容器在cgroup下的内存配置目录,查看内存配置文件发现内存使用限制为400M,内存和swap限制为500M

容器 镜像 容器 镜像预热_容器 镜像_64


通过查看配置文件发现内存限制为419430400b=400M,swap和内存共524288000b=500M