docker 1、docker常用命令与Dockerfile

1 docker基础


1.0 精简版命令
查看容器的id:
docker ps|grep <service_name>
查看容器的统计信息(包含cpu和内存使用情况等):
docker stats <container_id>
查看容器的日志信息:
docker logs <container-id>
打包镜像为tar格式文件:
docker save -o xxx.tar [Docker Registry地址]<仓库名>:<标签>
加载镜像:
docker load -i gnocchi-api.tar
删除镜像:
docker rmi <image_id>
删除容器:
docker rm <container_id>
查看镜像列表:
docker images
查看某个组件的镜像,以ceilometer为例
docker images|grep ceilometer
运行镜像:
docker run -it [Docker Registry地址]<仓库名>:<标签> /bin/bash
以root用户运行镜像:
docker run -it -uroot [Docker Registry地址]<仓库名>:<标签>
查看镜像分层信息:
docker history <image_id>
查看容器大小, 将container的文件系统进行打包:
docker export <container_id> -o xxx.tar
拷贝文件到容器中:
docker cp <file_path> <container_id>:<path>
提交容器为新的镜像:
docker commit <container_id> [Docker Registry地址]<仓库名>:<标签>
给镜像重新打标签:
docker tag [Docker Registry地址]<仓库名>:<标签> [Docker Registry地址]<仓库名>:<新标签>

1.1 安装docker
centos环境下:
yum install docker
systemctl enable docker
systemctl start docker
systemctl status docker

另一种安装方式:
配置国内源
sudo yum-config-manager --add-repo https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo
安装Docker CE
sudo yum makecache fast
sudo yum install docker-ce
启动Docker CE
sudo systemctl enable docker
sudo systemctl start docker
建立docker用户组
原因:docker命令用socker和Docker通讯,将需要使用的docker用户加入docker用户组
sudo groupadd docker
sudo usermod -aG docker $USER

解释:
groupadd :添加用户组
usermod 命令:修改用户,用户加目录
usermod -aG:追加用户组
$USER : 当前用户

镜像加速:
添加内核参数
sudo tee -a /etc/sysctl.conf <<-EOF
net.bridge.bridge-nf-call-ip6tables    =    1
net.bridge.bridge-nf-call-iptables    =    1
EOF


重新加载
sudo sysctl -p

解释:
/etc/sysctl.conf : 允许改变正在运行中的Linux接口的文件
sysctl -p <filename>  
p:指定路径,再如sysctl配置文件,如果没有指定路径,则加载/etc/sysctl.conf

镜像加速器:
/etc/docker/daemon.json 中写入内容
{
        "registry-mirrors":    [
                "https://registry.docker-cn.com"
        ]
}

重启服务
sudo systemctl daemon-reload
sudo systemctl restart docker


1.2 使用docker镜像
Docker运行容器前需要在本地存在对应镜像,如果本地不存在,会从镜像仓库下载

1.3 管理Docker镜像
1) 列出镜像:
docker images
等同于: docker image ls
镜像ID:是镜像的唯一标识,一个镜像也可对应多个标签
镜像体积:
Docker Hub显示的是压缩后的体积
docker images:显示镜像下载到本地展开后的大小

列出部分镜像:
docker images ubuntu

列出指定名称和标签的镜像
docker images ubuntu:14.04

中间层镜像:
默认只显示顶层镜像,希望包含中间层镜像,需要-a
docker images -a
是其他镜像所依赖的镜像。
 
2) 获取镜像:
docker pull [选项] [Docker Registry地址]<仓库名>:<标签>
解释:
Docker Registry地址: <域名/IP>[:端口号],默认时Docker Hub
仓库名:两段式名称,<用户名>/<软件名>,不给出用户名,
默认为library,也就是官方镜像

示例:
docker pull ubuntu:14.04

4) push镜像
docker pull [选项] [Docker Registry地址]<仓库名>:<标签>
示例:
docker push docker.io/chao/mongo:3.4.9

5) 以镜像为基础启动一个容器来运行。
docker run [option] <仓库>:<标签> 命令

示例: 以bash进行交互式操作
docker run -it -uroot --rm ubuntu:14.04 bash

解释:
docker run [option] <仓库>:<标签> 命令
docker run:运行容器的命令
-it: i交互式操作,t:终端
-uroot: 以root用户身份运行容器
--rm:容器推出后随之将其删除。默认退出容器不会立即删除
ubuntu:14.04 : 是指用ubuntu:14.04镜像为基础来期待哦改容器
bash : 放在镜像名后的是命令,希望交互式Shell,因此用bash
exit:退出容器

运行一个容器(不使用卷),做的任何文件修改会被记录到容器存储层里面。
而Docker提供了docker commit命令,可以将容器的存储层保存下来成为镜像。
本质:在原有镜像的基础上,再叠加容器的存储层,构成新的镜像。
运行新镜像:会拥有原有容器最后的文件变化

6) 删除镜像
删除镜像:
docker rmi [选项] <镜像1> [<镜像2>...]
docker rm 是删除容器

删除虚悬镜像:
docker rmi $(docker images -q -f dangling=true)
虚悬镜像:无标签的镜像
docker images -f dangling=true
删除虚悬镜像:
docker image prune

实际就是一个查询,删除所有仓库名为redis的镜像
docker rmi $(docker iamges -q redis)
删除mongo:3.2之前的镜像
docker rmi $(docker images -q -f before=mongo:3.2)

Centos中没有UnionFS驱动,使用devicemapper利用LVM进行分层存储
需要配置direct-lvm给devicemapper

Untagged和Deleted
镜像可以有多个标签,唯一标识是ID和摘要
步骤:
1 将要求的镜像标签取消,即untagged;删除指定标签
2 镜像所有标签被取消,从上层向基础层进行删除
3 有容器以该镜像为基础,再加上一层容器存储层,不可以
删除该镜像。应该先删除容器,再删除镜像


7) 从容器创建一个新的镜像
docker commit语法格式:
docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]

缺点:
不要使用docker commit定制镜像,定制镜像应该使用Dockerfile完成
镜像:是容器基础,每次执行docker run指定哪个镜像作为容器运行的基础
之前用Docker Hub的镜像,当不能满足需求,需要定制镜像。

示例:
docker commit fb447dba394f docker.io/chao/gnocchi-api:1.0
docker commit --author "Tao Wang <[email protected]>" --message "修改了默认网页" webserver nginx:v2 
查看历史:
docker history nginx:v2


慎用 docker commit
原因:
1) 无关文件被改动
2) docker commit对所有镜像操作是黑箱操作。
除了只做镜像的人知道执行过什么命令,别人无从得知。
3) 除当前层,之前的每一层都不会改变,每次修改即使删除上一层的
东西也不会丢失。镜像臃肿。
参考:
http://www.runoob.com/docker/docker-commit-command.html


8) 查看镜像大小
docker system df:
查看镜像,容器,数据卷所占用的空间

9) docker save和docker load
作用:将镜像保存为一个tar文件,然后传输到另一个位置上,再加载进来

打包镜像为tar格式文件:
docker save -o xxx.tar [Docker Registry地址]<仓库名>:<标签>
示例:
docker save -o gnocchi-api.tar docker.io/chao/gnocchi-api:1.0
加载镜像:
docker load -i xxx.tar

10) 查看镜像分层信息
docker history <image_id>


2 dockerfile基础


2.1 Dockerfile定制镜像
镜像定制=定制每一层需要添加的配置
Dockerfile:编写脚本来将每一层的修改写入
含义:是一个文本文件,包含许多指令。每条值另构建一层。
因此每一条值的内容,描述当层如何构建

2.2 FROM指定基础镜像
定制镜像:以一个镜像为基础,在上面进行定制。基础镜像必须指定。
FROM:指定基础镜像,一个Dockerfile中FROM是必备的值另,而且是第一条指令。
Docker中存在特殊镜像,名字叫做scratch。表示空白镜像。
FROM scratch
表示不以任何镜像为基础,接下来的指定将作为镜像第一层开始存在。

示例:
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

2.3 RUN执行命令
RUN:执行命令行命令
格式:
1) shell: RUN <命令>, 就像直接在命令行中输入的命令一样
例如:
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

2) exec格式: RUN ["可执行文件", "参数1", "参数2"], 更像是函数调用中格式
例如:
FROM    debian:jack
RUN    apt-get    update
RUN    apt-get    install    -y    gcc    libc6-dev    make
RUN    wget    -O    redis.tar.gz    "http://download.redis.io/releases/redis-3.2.5.tar.gz"
RUN    mkdir    -p    /usr/src/redis
RUN    tar    -xzf    redis.tar.gz    -C    /usr/src/redis    --strip-components=1
RUN    make    -C    /usr/src/redis
RUN    make    -C    /usr/src/redis    install

RUN处理过程:
新建立一层,在其上执行命令,执行结束,commit这一层修改,形成新的镜像
Union FS:有最大层数限制,不得超过127层

正确写法:
FROM    debian:jessie
RUN    buildDeps='gcc    libc6-dev    make'    \
                &&    apt-get    update    \
                &&    apt-get    install    -y    $buildDeps    \
                &&    wget    -O    redis.tar.gz    "http://download.redis.io/releases/redis-3.2.5.tar.gz"    \
                &&    mkdir    -p    /usr/src/redis    \
                &&    tar    -xzf    redis.tar.gz    -C    /usr/src/redis    --strip-components=1    \
                &&    make    -C    /usr/src/redis    \
                &&    make    -C    /usr/src/redis    install    \
                &&    rm    -rf    /var/lib/apt/lists/*    \
                &&    rm    redis.tar.gz    \
                &&    rm    -r    /usr/src/redis    \
                &&    apt-get    purge    -y    --auto-remove    $buildDeps

用一个RUN指令,用&&将各个命令串连起来
经验:定义每一层该如何构建
Dockerfile支持Shell类的行尾添加 \ 命令换行方式, # 进行注释
最后一步:清零下载,展开的文件

2.4 构建镜像 
注意不要遗漏".",这个表示指定上下文路径
docker build -t nginx:v3 .

docker build [选项] <上下文路径/URL/->
命令解释:
-t nginx:v3 ,指定最终镜像的名称

镜像构建上下文(Context)
docker build 原理: Docker运行时分为Docker引擎
(服务端守护进程)和客户端工具。
Docker引擎:提供REST API,称为Docker Remote API。
docker命令通过API与Docker引擎交互完成功能。
分析:实际就是ceilometer client和ceilometer的关系

docker build命令构建镜像:实际并非在本地构建,而是在服务端,
需要让服务端获得本地文件。
为了解决这个问题:
用户指定构建镜像上下文的路径,docker build命令的值路径后,会将
路径下所有内容打包,然后传给Docker引擎。Docker引擎收到包,获得
构建镜像所需文件。

Dockerfile中写:
COPY ./package.json /app/
解释:复制上下文目录下的package.json而不是docker build命令所在
目录下的package.json
这里的路径必须是相对路径。

[root@localhost mynginx]# docker build -t nginx:v3 .
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM nginx
 ---> 40960efd7b8f
Step 2/2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
 ---> Running in 2ef4ef6b24a2
 ---> bbf16584db00
Removing intermediate container 2ef4ef6b24a2
Successfully built bbf16584db00
Successfully tagged nginx:v3

经验:将Dockerfile放在空目录,或者项目根目录下。如果目录下没有所需文件,
需要把所需文件复制一份过来。
可以用 .gitignore 语法写一个 .dockerignore,该文件是用于剔除
不需要作为上下文传递给Docker引擎的。

-f ../Dockerfile.php 指定某个文件作为Dockerfile

其他docker build用法
用Git repo进行构建,
docker build https://github.com/twang2218/gitlab-ce-zh.git
解释:这个命令指定构建所需要的Git repo,并且指定默认的master分支
Docker会git clone该项目,切换到指定分支,进入到指定目录后开始构建

用给定的tar压缩包构建
docker build http://server/context.tar.gz

解释:
如果给定tar压缩包,则下载这个包,自动解压所,以其作为上下文,开始构建

从标准输入中读取Dockerfile进行构建
docker build - < Dockerfile

cat Dockergfile | docker build -
缺点:没有上下文,不可以将本地文件COPY进镜像

从标准输入中读取上下文压缩包进行构建
docker build - < context.tar.gz

Docker 1.13+使用docker image
docker image build

2.5 COPY命令
Dockfile指令详细解释
COPY复制文件
COPY <源路经>... <目标路径>
COPY ["<源路经1>",..."<目标路径>"]
和RUN指令一样,有两种格式,一种类似于命令行文件,一种类似于函数调用
COPY会把上下文目录中文件复制到新一层镜像内的 目标路径位置
COPY package.json /usr/src/app
源路经可以是多个,或通配符
COPY hom* /mydir
COPY hom?.txt /mydir/
目标路径: 可以是容器内绝对路径,也可以是相对工作目录的相对路径

2.6 ADD更高级的复制文件
ADD是在COPY基础上增加新功能
源路经:可以是URL,Docker引擎会下载链接文件当到目标路径,下载后文件权限设置为600.
若不是想要权限   :加额外的一层RUN进行权限调整。
如果下载的是压缩包:解压所需要额外一层RUN指令
不推荐使用

自动解压缩
FROM scratch
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /

ADD使用:自动解压缩,最好用COPY
缺点:会使得镜像构建缓存失效
原则:
所有的文件复制均使用COPY指令,仅在需要自动解压缩的场合使用ADD    

2.7 CMD容器启动命令
CMD指令和RUN相似
shell格式: CMD <命令>
exec格式 : CMD ["可执行文件", "参数1", "参数2"...]
参数列表格式: CMD["参数1", "参数2"...]
指定ENTRYPOINT指令后,用CMD指定具体的参数

容器:是进程。启动需要指定运行的程序和参数,
CMD指令:就是指定默认容器主进程的启动命令
ubuntu镜像默认的CMD是/bin/bash。可以在运行时指定运行别的命令
docker run -it ubuntu cat /etc/os-release

推荐:使用exec格式,该格式在解析时会被解析为JSON数组,使用双引号""
CMD echo $HOME
等同于
CMD ["sh", "-c", "echo $HOME"]

Docker不是虚拟机,容器中应用都在前台执行,容器没有后台服务的概念。
容器内执行server *** start, systemctl发现执行不了。
容器:启动程序是容器应用进程,为主进程而存在。
所以CMD service nginx start 等同于
CMD ["sh", "-c", "service nginx start"]
主进程实际是sh,正确做法是直接执行nginx可执行文件,并且要求以
前台形式运行:
CMD ["nginx", "-g", "daemon off;"]


2.8 ENTRYPOINT入口点
ENTRYPOINT分为exec格式和shell格式
作用:和CMD一样,在指定容器启动程序和参数
ENTRYPOINT:在运行时可以替代,需要通过
docker run的参数--entrupoint来指定。

指定ENTRYPOINT后,CMD含义发生改变,不再直接运行命令,
而是将CMD的内容作为参数传递给ENTRYPOINT指令。
<ENTRYPOINT> "<CMD>"

场景一:让镜像变成像命令一样使用
FROM ubuntu:16.04
FROM    ubuntu:16.04
RUN    apt-get    update    \
                &&    apt-get    install    -y    curl    \
                &&    rm    -rf    /var/lib/apt/lists/*
CMD    [    "curl",    "-s",    "http://ip.cn"    ]


FROM    ubuntu:16.04
RUN    apt-get    update    \
                &&    apt-get    install    -y    curl    \
                &&    rm    -rf    /var/lib/apt/lists/*
ENTRYPOINT    [    "curl",    "-s",    "http://ip.cn"    ]

当存在ENTRYPOINT后,CMD的内容会作为参数传递给ENTRYPOINT, -i 是新的CMD

场景二:应用运行前的准备工作
容器准备工作,写脚本,放入ENTRYPOINT中执行,脚本会将解到的参数作为命令

FROM    alpine:3.4
...
RUN    addgroup    -S    redis    &&    adduser    -S    -G    redis    redis
...
ENTRYPOINT    ["docker-entrypoint.sh"]
EXPOSE    6379
CMD    [    "redis-server"    ]

docker    run    -it    redis    id


2.9 ENV设置环境变量
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2> ...
例子:
ENV VERSION=1.0 DEBUG=on NAME="Happy Feet"

ENV NODE_VERSION 7.2.0

RUN    curl    -SLO    "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.ta
r.xz"    \
        &&    curl    -SLO    "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"    \
        &&    gpg    --batch    --decrypt    --output    SHASUMS256.txt    SHASUMS256.txt.asc    \
        &&    grep    "    node-v$NODE_VERSION-linux-x64.tar.xz\$"    SHASUMS256.txt    |    sha256sum    -c    -    \
        &&    tar    -xJf    "node-v$NODE_VERSION-linux-x64.tar.xz"    -C    /usr/local    --strip-components=1    \
        &&    rm    "node-v$NODE_VERSION-linux-x64.tar.xz"    SHASUMS256.txt.asc    SHASUMS256.txt    \
        &&    ln    -s    /usr/local/bin/node    /usr/local/bin/nodejs

2.10 ARG构建参数
格式: ARG <参数名>[=<默认值>]
不同点:ARG的环境变量是构建环境的环境变量,容器运行时不存在
docker build中用 --build-arg <参数名>=<值> 来覆盖


2.11 VOLUME 定义匿名卷
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>

容器运行时尽量保持存储层不发生写操作,对于数据库类需要保存动太数据的应用,数据库
文件应该保存在卷中
为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在Dockerfile中,可以将实现指定的目录挂载为匿名卷
VOLUME /data
/data目录会在运行时自动挂载为匿名卷。

覆盖挂载设置:
docker run -d -v mydata:/data xxxx

2.12 EXPOSE声明端口
EXPOSE <端口1> [<端口2>...]
声明运行时容器提供的服务端口,不会在运行时,因为声明应用就会开启这个端口的服务。
好处:
1) 理解镜像服务守护端口,方便配置映射
2) 在运行时使用随机端口映射, docker run -p, 会自动随机映射EXPOSE端口

Docker --icc=false,容器间默认无法互相访问
--links参数的容器才可以互通,EXPOSE中所声明的端口才可以被访问

docker network:可以自定义网络实现容器互联与隔离
EXPOSE和运行时使用 -p <宿主端口>:><容器端口>
-p : 映射宿主端口和容器端口,将容器端口服务给外界访问
EXPOSE:仅声明容器打算用什么端口,不会进行端口映射


2.13 WORKDIR指定工作目录
WORKDIR <工作目录路径>
作用:指定工作目录(或者称为当前目录),各层的当前目录被改为指定目录,
如果目录不存在,WORKIDIR会建立目录。

在shell中连续两行时同一个进层执行环境
Dockerfile中,两行RUN命令执行环境根本不同,是不同容器
RUN cd /app
RUN echo "hello" > world.txt
这个会执行错误。
如果需要改变以后各层工作目录位置,应该使用WORKDIR指令。


2.14 USER指定当前用户
USER <用户名>
和WORKDIR相似,改变环境状态并影响以后的层。
USER:改变之后层的执行RUN, CMD以及ENTRYPOINT命令的身份。
限制:用户必须事先建立好的
RUN groupadd -r redis && useradd -r -g redis redis
USER redis
RUN [ "redis-server" ]

root执行脚本,用gosu
#    建立    redis    用户,并使用    gosu    换另一个用户执行命令
RUN    groupadd    -r    redis    &&    useradd    -r    -g    redis    redis
#    下载    gosu
RUN    wget    -O    /usr/local/bin/gosu    "https://github.com/tianon/gosu/releases/download/1.7/
gosu-amd64"    \
                &&    chmod    +x    /usr/local/bin/gosu    \
                &&    gosu    nobody    true
#    设置    CMD,并以另外的用户执行
CMD    [    "exec",    "gosu",    "redis",    "redis-server"    ]

解释:
groupadd -r :常见系统工作组
useradd -r -g: 
-r创建系统用户, -g:指定用户登陆组的GID或者组名

2.15 HEALTHCHECK
HEALTHCHECK [选项] CMD <命令> : 设置检查容器健康状况的命令
HEALTHCHECK NONE:屏蔽健康检查指令
作用:判定容器主进程的服务状态是否正常
初始状态:starting,检查成功后变为healthy
失败:unhealthy
--interval=<间隔> :
--timeout=<时长> : 命令运行超时,则视为失败
--retries=<次数> : 当连续失败指定次数后,容器状态视为unhealthy,默认3此


FROM    nginx
RUN    apt-get    update    &&    apt-get    install    -y    curl    &&    rm    -rf    /var/lib/apt/lists/*
HEALTHCHECK    --interval=5s    --timeout=3s    \
        CMD    curl    -fs    http://localhost/    ||    exit    1


2.16 ONBUILD
ONBUILD <其他指令>
含义:后面根其他指令,如 RUN, COPY等。当前镜像构建时不会被执行,
以当前镜像为基础构建下一级镜像才会被执行
应用场景:基础镜像,各个项目使用这个基础镜像,重新构建继承基础镜像的更新

FROM my-node
好处:当前层构建的时候,命令不会被执行;放到下一层去执行

其他生成镜像的方法:
1) 从rootfs压缩包导入
docker import [选项] <文件>|<URL>|- [<仓库名>[:<标签>]]
压缩包可以时本地文件,远程web完呢建等。
压缩包会在镜像目录展开,作为镜像第一层提交

2) docker import生成
docker import http://download.openvz.org/template/precreated/ubuntu-14.04-x86_64-minimal.tar.gz openvz/ubuntu:14.04 
解释:自动下载文件作为根问建系统展开导入,并保存为镜像 openvz/ubuntu:14.04


3 docker原理


3.1 镜像的实现原理
使用Union FS将不同的层结合到一个镜像中去
Union FS的用途:
1) 将多个disk挂到同一个目录下
2) 将读分支和写分支联合

3.2 镜像特点
是多层存储,每一层是在前一层的基础上进行修改;
容器也是多层存储,是以镜像为基础层,在上面加上一层作为容器运行的存储层。

3.3 下载镜像
下载:分层存储,镜像时由多层存储构成,下载也是
一层一层下载。

3.4 Docker容器
容器:独立运行的一个或一组应用,以及运行环境。
可以认为容器是镜像的一次运行。

4 kolla


kolla项目可以用来生成容器运行所需的镜像。


参考:
[1] https://yeasy.gitbooks.io/docker_practice/introduction/
[2] https://www.gitbook.com/book/yeasy/docker_practice/details
[3] https://github.com/openstack/kolla

猜你喜欢

转载自blog.csdn.net/qingyuanluofeng/article/details/86683198