2017/03 Chenxinphp
参考
https://yeasy.gitbooks.io/docker_practice Docker入门与实践 电子书,截止201807一直在更新.
http://guide.daocloud.io/dcs/daocloud-services-9152632.html Docker加速器
https://blog.csdn.net/S_gy_Zetrov/article/details/78161154 入门
http://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html
http://www.ruanyifeng.com/blog/2018/02/docker-wordpress-tutorial.htmlhtml
命令自动补全(不属于docker内容)
安装(仅支持较新的linux版本)java
yum install bash-completion
说明(能够忽略)
最小化安装centos7须要安装一个 bash-completion 包,而后退出 bash,从新登陆便可.
bash-2.05及之后的版本提供了自动补齐的编程接口.
bash-completion的安装已加入Centos7初始化脚本.node
yum install docker # 安装 docker version docker info docker search centos docker pull centos:latest docker image ls --all docker image rmi image_id # 删除 docker image save image_id -o centosvim.tar # 输出一个tar格式的 docker image load -i centosvim.tar # 载入一个tar格式的 docker image tag image_id centosvim:1.0 docker image inspect image_id #获取镜像元数据 docker container ls --all docker container attach container_id # ctrl+p, ctrl+q 将容器推到后台后,推荐使用exec方式进入,防止退出的时候错误的将容器终止了(Ctrl+d) docker container exec -it container_id /bin/bash # 推荐 docker container exec -it --user root container_id /bin/bash #登录容器,并成为root docker container run -it --name container_name image_id /bin/bash #启动一个容器 docker container run -d -p 1022:80 foo/live /bin/bash #物理机的1022映射到docker的80; docker container run -d -p 127.0.0.2:8080:80 --rm --name wordpress --env WORDPRESS_DB_PASSWORD=123456 --link wordpressdb:mysql --volume "$PWD/wordpress":/var/www/html wordpress docker container run -p 1022:80 -it centos:lastest /bin/bash docker container port container_id docker container inspect container_id #获取容器元数据 docker container cp container_id:[/path/to/file] /local/path/dir/ docker container commit -m "centos with vim" -a "chenxin" container_id chenxin/centos:vim docker container rm container_id docker container prune #删除全部处于stop状态的container docker container stats container_id #显示当前运行的这个容器资源占用状况(CPU/MEM/NET/IO/PIDS) docker container top container_id #显示容器中当前运行的pid信息 docker container start container_id docker container stop container_id ctrl+p ctrl+q # 容器正常运行,用户临时退出bash exit / ctrl+d # 用户退出,可能致使容器stop docker diff container_id # 查看容器存储层改动记录 docker history image_id # 查看image内的历史记录(每层改动状况) docker build -t xbzj . # 使用Dockerfile构建镜像
普通用户执行docker指令须要的权限
xbzj帐号执行 docker search java
报错Got permission denied while trying to connect to the Docker daemon socket at ...permission denied
将xbzj加入到docker用户组就能够了: usermod -G docker xbzjmysql
网络说明
因大陆访问海外download.docker.com存在网络问题.可使用rpm方式安装.以后可使用大陆第三方提供的Docker库(好比阿里云,或daocloud)
AWS上自己有docker库,能够直接yum安装.若是增长yum源安装官网版本,须要解决一些依赖问题.
建议采起yum方式安装(AWS默认的yum源)
docker分为社区版(ce)和企业版(ee收费)
官方安装文档 https://docs.docker.com/install/linux/docker-ce/centos/#uninstall-old-versionslinux
yum安装方式
a.配置yum仓库(aws不需此步骤)
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
ls /etc/yum.repos.d/
amzn-main.repo docker-ce.reponginx
b.正式安装
yum install docker-ce
这里会报依赖错误.能够自行解决.或使用AWS自身的yum源(推荐)
yum install docker (aws只须要这一步就能够了)git
rpm安装方式
https://download.docker.com/linux/centos/7/x86_64/stable/Packages/
https://download.docker.com/
rpm安装完成后,执行rpm -ql docker
/etc/rc.d/init.d/docker #启动关停状态查看脚本
/etc/sysconfig/docker #配置文件,能够配置docker的一些目录信息和日志信息
/etc/sysconfig/docker-storage #文件配置
/etc/udev/rules.d/80-docker.rules
/usr/bin/docker
/usr/bin/docker-containerd
/usr/bin/docker-containerd-shim
/usr/bin/docker-ctr
/usr/bin/docker-init
/usr/bin/docker-proxy
/usr/bin/docker-runc
/usr/bin/dockerd
/usr/share/bash-completion/docker
/usr/share/vim/vimfiles/syntax/dockerfile.vim
/var/lib/docker #主要目录github
安装完成后的验证
执行docker version
Client:
Version: 18.03.1-ce #这个是aws本身的版本,是18年03月作的AMI.web
docker主要目录说明
ls /var/lib/docker/
builder containerd containers image network overlay2 plugins runtimes swarm tmp trust volumes
/var/lib/docker/devicemapper/devicemapper/data #用来存储相关的存储池数据
/var/lib/docker/devicemapper/devicemapper/metadata #用来存储相关的元数据。
/var/lib/docker/devicemapper/metadata/ #用来存储 device_id、大小、以及传输_id、初始化信息
/var/lib/docker/devicemapper/mnt #用来存储挂载信息
/var/lib/docker/container/ #用来存储容器信息
/var/lib/docker/graph/ #用来存储镜像中间件及自己详细信息和大小 、以及依赖信息
/var/lib/docker/repositores-devicemapper #用来存储镜像基本信息
/var/lib/docker/tmp #docker临时目录
/var/lib/docker/trust #docker信任目录
/var/lib/docker/volumes #docker卷目录
docker启停
service docker start 或者 systemctl start docker
查询镜像
docker search centos
拉取
docker pull centos
或者
docker pull centos:latest
会默认放到/var/lib/docker/overlay2/目录,进入查看以下:
ls /var/lib/docker/overlay2/00...28/diff
bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
目录和文件内容跟咱们安装系统后的相同(连日志都有了).
镜像源地址
a.查看镜像源地址
docker info
b.修改镜像源地址(2种方式)
1.增长或修改/etc/docker/daemon.json (18.03版本后就没有这个文件了aws的centos18.03版本.只能新增.1.13版本有这个文件centos7yum安装)
{ "registry-mirrors": ["http://hub-mirror.c.163.com"] }
2.修改或新增 /etc/sysconfig/docker,在OPTIONS变量后追加参数
OPTIONS="--default-ulimit nofile=1024:4096 --registry-mirror=https://docker.mirrors.ustc.edu.cn"
修改完成后,重启docker.通过测试,以上2个地址均可用.
Docker国内源
a.国内源
Docker 官方中国区 https://registry.docker-cn.com
中国科技大学 https://docker.mirrors.ustc.edu.cn
网易 http://hub-mirror.c.163.com
阿里云 https://pee6w651.mirror.aliyuncs.com
默认docker源: Registry: https://index.docker.io/v1/
b.加速器
须要注册的加速器使用说明:
登录阿里云docker的registry:(须要先注册阿里云帐号,在容器镜像服务里配置registry密码.将生成的镜像url复制到docker配置文件里,相似:https://2r6ncmdxli.mirror.aliyuncs.com 的地址.
docker login --username=chenxin6676 registry.cn-shanghai.aliyuncs.com
以后在本地能够push镜像到阿里云.
查看docker镜像版本
查看docker镜像的版本号TAG,从远程仓库拉取本身想要版本的镜像.须要在docker hub查看
地址以下:https://hub.docker.com/r/library/
进入以后,在页面左上角搜索框搜索.
点击 详情->TAG.
docker pull java:latest
1 查看本地镜像
docker image ls --all
2 容器启动参数
docker container run -it --name test image_id /bin/bash
具备自动抓取 image 的功能.若是发现本地没有指定的 image 文件,就会从仓库自动抓取.
-t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上
-i 则让容器的标准输入保持打开
--name test:容器的名字叫作test.
docker container run --rm --name wordpress --volume "$PWD/":/var/www/html php:5.6-apache
--rm:中止运行后,自动删除容器文件.
--volume "$PWD/":/var/www/html:将宿主机当前目录($PWD变量内容)映射到容器的/var/www/html.
php:5.6-apache : 来源镜像
docker container run -d --rm --name wordpressdb --env MYSQL_ROOT_PASSWORD=123456 --env MYSQL_DATABASE=wordpress mysql:5.7
-d:容器启动后,在后台运行.
--env MYSQL_ROOT_PASSWORD=123456:向容器进程传入一个环境变量MYSQL_ROOT_PASSWORD,该变量会被用做 MySQL 的根密码.
--env MYSQL_DATABASE=wordpress:向容器进程传入一个环境变量MYSQL_DATABASE,容器里面的MySQL会根据该变量建立一个数据库wordpress
mysql:5.7 : 来源镜像
docker container run -d -p 127.0.0.2:8080:80 --rm --name wordpress --env WORDPRESS_DB_PASSWORD=123456 --link wordpressdb:mysql --volume "$PWD/wordpress":/var/www/html wordpress
-p 127.0.0.2:8080:80:物理机127.0.0.2的8080映射到器的 80 端口.
--link wordpressdb:mysql,表示 wordpress 容器要连到(先前建立的)wordpressdb容器,冒号表示该容器的别名是mysql.
浏览器访问物理机127.0.0.2:8080就能看到 WordPress 的安装提示了.并且,你在wordpress子目录下的每次修改,都会反映到容器里面.
最后,终止上面这两个容器(--rm,容器文件会自动删除): docker container stop wordpress wordpressdb
docker container run -d -p 10.0.0.10:8080:80 --volume /home/admin/www/:/usr/local/apache2/htdocs --name apache httpd 或者 docker container run -d -p 8080:80 --volume ...xxx...
以上使用一个httpd的镜像建立一个apache的容器
docker启动容器的时候,能够指定容器的IP地址,但须要额外配置网络模式,具体请参考网上资料https://blog.csdn.net/sbxwy/article/details/78962809 .
3 detach容器
若是想让容器一直运行,而不是中止,可使用快捷键 ctrl+p ctrl+q 退出,此时容器的状态为Up.
4 attach进入到这个容器
exec方式进入(run的时候没有指定 -it /bin/bash的)容器
docker container exec -it [containerID] /bin/bash
若是docker run命令运行容器的时候,没有使用-it参数,就要用这个命令进入容器.一旦进入了容器,就能够在容器的 Shell 执行命令了.
docker container attach container_id # 不推荐此方式.推荐exec方式,由于attach完,直接ctrl+d,容器状态会变成exited.而exec不会.
5 终止容器(多种方式)
在容器内,使用 exit,命令退出,则容器的状态处于Exit,而不是后台运行.
或者 docker container stop [containID]
或者 docker container kill [containID]
6 查看当前运行的容器/已中止的容器
docker container ls 同 docker ps (查看正在run中的容器) docker container ls --all 同 docker ps -a 查看全部容器,包括中止的(Exited状态) docker container rm `docker container ls -aq` 只列出docker container的id,并删除掉全部container.
7 启动、中止、重启容器
docker container start ca5b2982c795 #[containID] docker container stop ca5b2982c795 docker container restart ca5b2982c795 docker stop $(docker ps -aq) 中止全部的容器
8 与宿主机间对拷文件
docker container cp [containID]:[/path/to/file] /local/path/dir/ # 拷贝容器内文件到物理机上
9 commit指令
commit利用container建立image.
应用场合,好比被入侵后保存现场等。可是,不要使用 docker commit 定制镜像,定制镜像应该使用 Dockerfile 来完成。
docker container commit -m "centos with vim" -a "chenxin" container_id chenxin/centos:vim
-m指定说明信息;
-a指定用户信息;
ca5b2982c795表明容器的id;
chenxin/centos:vim指定目标镜像的用户名、仓库名和 tag 信息.
查看咱们刚刚建立镜像对应生成的文件
/var/lib/docker/image/overlay2/imagedb/metadata/sha256/38...348/ 这里是lastUpdated和parent的2个文本文件说明(起源于哪一个镜像).
/var/lib/docker/image/overlay2/imagedb/content/sha256/38...348 这个文本文件详细说明了这个镜像的配置信息
10 删除 容器/镜像
删除单个容器 docker container rm [containerID] (非运行状态的才容许删除,不然请先docker stop/kill) 删除所有容器 docker container rm `docker container ls -aq` 或 docker container rm `docker ps -aq` 删除单个镜像 docker image rmi image_id 删除全部镜像 docker image rmi `docker image ls -aq` 删除全部在 mongo:3.2 以前的镜像:docker image rmi $(docker image ls -q -f before=mongo:3.2) # -f为filter. 删除一个运行中的容器,能够添加 -f 参数 docker container rm -f myweb 删除全部处于终止状态的容器 docker container prune docker rm : 删除一个或多个 容器 docker rmi : 删除一个或多个 镜像 docker prune: 用来删除再也不使用的 docker 对象
11 将image导出后再导入其余装了docker的机器
docker image save image_id -o centosvim.tar #如何将本身的image硬拷贝 docker image load -i centosvim.tar #将tar文件拷贝到其余机器后,执行导入image docker image tag 38f309423638 centosvim:1.0 #上面的REPOSITORY/TAG都是none,那么能够tag
12 push本身的image到第三方仓库(aws)
a.将本身的image给push到docker官方的hub
这里须要到官方注册帐号才行.须要先登陆 docker login;而后 docker push chenxin/centos:vim .这样之后能够经过本身的帐号能够从官网pull下来本身的image.
b.将image给push到aws的ECR(ERS)
docker build -t xbzj . # 首先本地构建镜像,以xbzj为例 aws ecr get-login --no-include-email --region ap-southeast-1 #执行awscli指令获取登录ECR命令 docker login -u AWS -p eyJwY...M30= https://61..9551.dkr.ecr.a..t-1.amazonaws.com #根据上条命令输出登录token,登录完成. docker tag xbzj:latest 61..51.dkr.ecr.ap-southeast-1.amazonaws.com/xbzj:latest #对image打TAG docker push 615..51.dkr.ecr.ap-southeast-1.amazonaws.com/xbzj:latest #将本地image给PUSH到ECR
13 端口映射NAT
docker启动服务,开启端口,如何映像到外部的IP和端口,从而对外提供服务(2种方式).
容器中启动的服务,能够经过宿主机直接访问(route物理机会看到172.17.0.0的路由docker0),但外部机器没法访问,那么就须要将docker端口映射到宿主机端口上.
查看物理机路由表,执行
# route Destination Gateway Genmask Flags Metric Ref Use Iface 172.17.0.0 * 255.255.0.0 U 0 0 0 docker0
2种方式,以下:
1.经过容器指令(推荐)
docker container run -d -p 1022:80 foo/live /bin/bash #物理机的1022映射到docker的80; docker container run -p 1022:80 -it centos:lastest /bin/bash #将物理机的1022端口映射docker的80端口 docker container run -d -p 10.0.0.10:1022:80 --volume /home/admin/www/:/usr/local/apache2/htdocs --name apache httpd # 指定了映射到哪一个物理网卡 docker container run -d -P image_id #这里的大写P,会将物理机随机1个端口映射到Dockfile文件EXPOSE声明的端口上.
2.经过iptables的映射
docker inspect container_id |grep IPAddress ->172.17.0.2 iptables -t nat -A DOCKER -p tcp --dport 8001 -j DNAT --to-destination 172.17.0.2:8000 # 将物理机的8001映射到容器的8000. 进入docker container里,启动httpd服务,并netstat检查:/usr/sbin/httpd 检查物理机端口开放: tcp 0 0 :::8000 :::* LISTEN 14066/docker-proxy
14 容器的 volume 子命令 (或 -v)
docker专门提供了volume子命令来操做数据卷:
create 建立数据卷
inspect 显示数据卷的详细信息
ls 列出全部的数据卷
prune 删除全部未使用的 volumes,而且有 -f 选项
rm 删除一个或多个未使用的 volumes,而且有 -f 选项
15 关于容器和镜像的挂载卷说明
一.经过docker run命令.在docker run后的 -v 指令(只对建立的容器有效)
一、运行命令:docker run --name test -it -v /home/xqh/myimage:/data ubuntu /bin/bash -> 主机上的 /home/xqh/myimage 目录中的内容关联到 容器中设置了一个挂载点 /data.在容器仍是主机上操做它,都是彻底实时同步的(实际指向的物理空间彻底相同). 二、运行命令:docker run --name test1 -it -v /data ubuntu /bin/bash ->docker会自动绑定主机上的一个目录到容器的/data上。(其目的不是让在主机上修改,而是让多个容器共享。)
二.经过dockerfile建立镜像声明的挂载点.
经过dockerfile的 VOLUME 方式对镜像有效.(在镜像中建立挂载点).与容器-v参数相比,有一个区别是,经过 VOLUME 指令建立的挂载点,没法指定主机上对应的目录,是自动生成的。
FROM ubuntu MAINTAINER hello1 VOLUME ["/data1","/data2"]
上面的dockfile文件经过VOLUME指令指定了两个挂载点 /data1 和 /data2. 若是用此镜像建立容器,则容器中的/data1和/data2是随机挂载的物理主机上的目录.
三.容器共享卷(挂载点) --volumes-from (会将原容器的dockerfile中声明的数据卷共享到本身这个容器上来,以便保持这个目录与原容器的一致)
docker run --name test1 -it myimage /bin/bash #myimage是用前面的dockerfile文件构建的镜像。 这样容器test1就有了 /data1 和 /data2两个挂载点。 下面咱们建立其余容器能够和test1共享 /data1 和 /data2卷 ,在 docker run中使用 --volumes-from标记,如: 来源不一样镜像,如:docker run --name test2 -it --volumes-from test1 ubuntu /bin/bash 来源相同镜像,如:docker run --name test3 -it --volumes-from test1 myimage /bin/bash 上面的三个容器 test1 , test2 , test3 均有 /data1 和 /data2 两个目录,且目录中内容是共享的,任何一个容器修改了内容,别的容器都能获取到。
四.最佳实践:数据容器
若是多个容器须要共享数据(如持久化数据库、配置文件或者数据文件等),能够考虑建立一个特定的数据容器,该容器有1个或多个卷。其它容器经过--volumes-from 来共享这个数据容器的卷。
由于容器的卷本质上对应主机上的目录,因此这个数据容器也不须要启动。如: docker run --name dbdata myimage echo "data container"
说明:有个卷,容器之间的数据共享比较方便,但也有不少问题须要解决,如权限控制、数据的备份、卷的删除等。这些内容之后介绍。
16 对比 mount 挂载数据卷 方式 的说明
以前咱们使用 --volume(-v) 选项来挂载数据卷,如今 docker 提供了更强大的 --mount 选项来管理数据卷。mount 选项能够经过逗号分隔的多个键值对一次提供多个配置项,所以 mount 选项能够提供比 volume 选项更详细的配置。使用 mount 选项的经常使用配置以下:
type 指定挂载方式,咱们这里用到的是 volume,其实还能够有 bind 和 tmpfs。
volume-driver 指定挂载数据卷的驱动程序,默认值是 local。
source 指定挂载源,对于一个命名的数据卷,这里应该指定这个数据卷的名称.在使用时能够写source,也能够简写为 src
destination 指定挂载的数据在容器中的路径。在使用时能够写 destination,也能够简写为 dst 或 target。
readonly 指定挂载的数据为只读。
volume-opt 能够指定屡次,用来提供更多的 mount 相关的配置。
下面咱们看个具体的例子:
$ docker volume create hello
$ docker run -id --mount type=volume,source=hello,target=/world ubuntu /bin/bash
咱们建立了名称为 hello 的数据卷,而后把它挂在到容器中的 /world 目录。经过 inspect 命令查看容器的详情中的 "Mounts" 信息能够验证.
使用 volume driver 把数据存储到其它地方
除了默认的把数据卷中的数据存储在宿主机,docker 还容许咱们经过指定 volume driver 的方式把数据卷中的数据存储在其它的地方,好比 AWS 的 S3。
简单起见,咱们接下来的 demo 演示如何经过 vieux/sshfs 驱动把数据卷的存储在其它的主机上。
docker 默认是不安装 vieux/sshfs 插件的,咱们能够经过下面的命令进行安装:
$ docker plugin install --grant-all-permissions vieux/sshfs
而后经过 vieux/sshfs 驱动建立数据卷,并指定远程主机的登陆用户名、密码和数据存放目录:
docker volume create --driver vieux/sshfs \ -o sshcmd=nick@10.32.2.134:/home/nick/sshvolume \ -o password=yourpassword \ mysshvolume
注意,请确保你指定的远程主机上的挂载点目录是存在的(demo 中是 /home/nick/sshvolume 目录),不然在启动容器时会报错。
最后在启动容器时指定挂载这个数据卷:
docker run -id \ --name testcon \ --mount type=volume,volume-driver=vieux/sshfs,source=mysshvolume,target=/world \ ubuntu /bin/bash
这就搞定了,你在容器中 /world 目录下操做的文件都存储在远程主机的 /home/nick/sshvolume 目录中。进入容器 testcon 而后在 /world 目录中建立一个文件,而后打开远程主机的 /home/nick/sshvolume 目录进行查看,你新建的文件是否是已经出如今那里了!
17 物理机与运行中的容器 数据的覆盖问题
以物理机器下的卷优先,以有数据的优先.
18 查看输出和日志(重要,经常使用)
docker container logs [container-id/names] # 获取容器的输出信息(相似控制台输出等)
docker container logs service-match|tail -n 100
19 控制容器占用系统资源(CPU,内存)
docker create 或者 docker run 的时候
-c|–cpu-shares[=0]参数来调整同期使用CPU的权重.
-m|–memory参数来调整容器使用内存的大小.
1.从官方pull一个registery的镜像,经过该镜像与物理机本地文件作好 --volume
2.修改物理机的镜像源站地址
能够参考
https://cloud.tencent.com/developer/article/1015137
https://juejin.im/post/5a4ac6806fb9a045104ad7c8
其余概念
仓库(Repository) 是存放一组关联镜像的集合,好比同一个应用的不一样版本的镜像,
注册服务器(Registry) 是存放实际的镜像的地方,
注册索引(Index) 则负责维护用户的帐号,权限,搜索,标签等管理。
注册服务器利用注册索引来实现认证等管理。
构建镜像
FROM centos-base:latestMAINTAINER artemus717@gmail.com ENTRYPOINT ["/config/bootstrap.sh"] CMD ["/bin/bash"]
此处指定了ENTRYPOINT、CMD命令.CMD命令为bash,咱们构建的镜像必定是有bash进程的,有问题能够直接进行排查.
准备bootstrap.sh
在容器内部,编写脚本,脚本内容直接复制
mkdir /config mkdir /config/init vi /config/bootstrap.sh chmod 755 /config/bootstrap.sh
问题
在你的Dockerfile中
RUN service mysql restart && /tmp/setup.sh
首先,docker镜像不快照您的运行进程,您的RUN命令只是在docker构建阶段运行,您须要指定命令运行时容器开始使用CMD或ENTRYPOINT命令,如 CMD mysql start
其次Docker容器须要进程(最后一个命令)保持运行,不然容器将退出.所以正常的服务mysql启动命令不能直接在Dockerfile中使用
解决方案:为了保持进程正常运行:
一般方式Dockerfile
使用service命令,并附加非end命令后,像tail -F,以下:
CMD service mysql start && tail -F /var/log/mysql/error.log
或使用前台命令来执行此操做,以下:
CMD /usr/bin/mysqld_safe
可否将脚本放到/etc/rc.local 来实现呢?通过测试,貌似不行,缘由应该是执行完后,自动退出了当前shell进程.
启动流程
docker run -it ubuntu /bin/bash 首先系统要有一个docker daemon的后台进程在运行,当刚才这行命令敲下时:
关闭流程
docker stop (默认会10秒超时后再kill)或直接docker kill(直接kill -9) .stop的话,会保持现场到磁盘,优雅的关闭.
容器状态说明
Up 正在运行 Exited 已经中止 Created 已建立未运行
持久化涉及到的外挂数据卷(有状态,紧耦合类的应用)
默认不挂载外部存储,则数据会和容器同生共死(违背了计算和数据分离原则),为容器的迁移或者故障恢复制造了麻烦。
因此通常采用-v参数挂外部卷.rm掉旧容器再从新run一个,把-v的卷挂回去就恢复了。
另外-v能够挂多个物理磁盘或者外部存储,也解决了io瓶颈的问题。
通常设置Volume的场景:
配置文件目录,数据文件目录,重要的日至文件目录.
须要先apt-get update,这个命令的做用是:同步 /etc/apt/sources.list 和 /etc/apt/sources.list.d 中列出的源的索引,这样才能获取到最新的软件包.不然安装的时候会提示:E: Unable to locate package xxx(如vim)
vim 安装 apt-get install vim
net-tools工具包 (含netstat route ifconfig mii-tool arp 等) apt-get install net-tools
procps工具包 (含 ps free ) apt-get install procps
rcconf (相似ntsyv,图形界面配置服务) apt-get install rcconf
update-rc.d (debian默认已安装,功能相似chkconfig)
iputils-ping (ping功能)
201807 Chenxin
参考
docker从入门到实践(一直更新): https://yeasy.gitbooks.io/docker_practice/image/build.html
Dockerfile实践: https://www.cnblogs.com/jsonhc/p/7767669.html
xbzj的Dockerfile文件,请参见"k8s笔记内容".
dockerfile概念说明
在空目录中,建立Dockerfile文件.Dockerfile指令.大小写不敏感(推荐大写)
FROM nginx RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
镜像构建上下文(Context)
docker build 命令最后有一个"."表示当前目录,这里是指明了上下文路径(context的路径),而非指明Dockerfile文件所在路径.
Docker 在运行时分为 Docker 引擎(服务端守护进程)和客户端工具。Docker 的引擎提供了一组 REST API,被称为 Docker Remote API,而如 docker 命令这样的客户端工具,则是经过这组 API 与 Docker 引擎交互,从而完成各类功能。所以,虽然表面上咱们好像是在本机执行各类 docker 功能,但实际上,一切都是使用的远程调用形式在服务端(Docker 引擎)完成。也由于这种 C/S 设计,让咱们操做远程服务器的 Docker 引擎变得简单.
当咱们进行镜像构建的时候,并不是全部定制都会经过 RUN 指令完成,常常会须要将一些本地文件复制进镜像,好比经过 COPY 指令、ADD 指令等。而 docker build 命令构建镜像,其实并不是在本地构建,而是在服务端,也就是 Docker 引擎中构建的。那么在这种C/S的架构中,如何才能让服务端得到本地文件呢?
这就引入了上下文的概念。当构建的时候,用户会指定构建镜像上下文的路径,docker build 命令得知这个路径后,会将路径下的全部内容打包,而后上传给 Docker 引擎。这样 Docker 引擎收到这个上下文包后,展开就会得到构建镜像所需的一切文件。
若是在 Dockerfile 中这么写: COPY ./package.json /app/
这是复制 上下文(context) 目录下的 package.json。所以,COPY 这类指令中的源文件的路径都是相对路径。若是真的须要那些并不在context目录下的文件,应该将它们复制到context目录中去。
若是观察 docker build 输出,咱们其实已经看到了这个发送上下文的过程:
$ docker build -t nginx:v3 . Sending build context to Docker daemon 2.048 kB ...
通常,应该将 Dockerfile 置于一个空目录下,或者项目根目录下。若是该目录下没有所需文件,那么应该把所需文件复制一份过来。若是目录下有些文件不但愿构建时传给 Docker 引擎,那么能够用".dockerignore"(剔除文件列表,不传递给 Docker 引擎).
那么为何会有人误觉得"."是指定 Dockerfile 所在目录呢?在默认状况下,若是不额外指定 Dockerfile 的话,会将上下文目录下的名为 Dockerfile 的文件做为 Dockerfile。实际上 Dockerfile 的文件名并不要求必须为 Dockerfile,且并不要求必须位于上下文目录中,好比能够用
-f ../docker-file.txt
参数指定某个文件做为 Dockerfile。
固然,通常你们习惯性的会使用默认的文件名 Dockerfile,以及会将其置于镜像构建上下文目录中。
FROM
指定基础镜像
LABEL
可选的
RUN
执行命令.制做image过程当中执行的事项.每执行1次RUN,就会构建1个临时image.
其格式有两种:
* shell 格式:RUN <命令>,就像直接在命令行中输入的命令同样.RUN <cmd> 这个会看成/bin/sh -c “cmd” 运行。 RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html * exec 格式:RUN ["可执行文件", "参数1", "参数2"],这更像是函数调用中的格式。 RUN ["executable", "arg1", .. ],Docker把他看成json的顺序来解析,所以必须使用双引号,并且executable须要完整路径.
Dockerfile 中每个指令都会创建一层.不少初学者制做出很臃肿的镜像缘由之一,就是忘记了每一层构建的最后没有清理掉无关文件.
CMD
执行指令或传递参数
执行container时候的默认启动命令.可能会被覆盖(好比,当运行container的时候声明了command,则再也不用image中的CMD定义的命令)
一个Dockerfile中定义多个CMD的时候,只有最后一个才会起做用.
CMD定义的三种方式: CMD <cmd> 这个会看成/bin/sh -c "cmd"来执行 # shell方式 CMD ["executable","arg1",....] # 推荐exec方式 CMD ["arg1","arg2"],这个时候CMD做为ENTRYPOINT的参数
对容器而言,启动程序就是启动容器应用进程. 容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,不会关心辅助进程.
而使用 service nginx start 命令,则是但愿用 upstart 方式之后台守护进程形式启动 nginx 服务。而刚才说了 CMD service nginx start 会被理解为 CMD [ "sh", "-c", "service nginx start"],所以主进程其实是 sh。那么当 service nginx start 命令结束后,sh 也就结束了,sh 做为主进程退出了,天然就会令容器退出。
正确的作法是直接执行 nginx 可执行文件,而且要求之前台形式运行。好比:
CMD ["nginx", "-g", "daemon off;"]
EXPOSE
声明端口 EXPOSE <端口1> [ <端口2> ...]
声明运行时容器提供服务端口,这只是一个声明,在运行时并不会由于这个声明应用就会开启这个端口的服务。此声明有两个好处
1.帮助使用者理解服务的守护端口,以便配置映射.
2.启动容器时,指定 docker run -P 时,会将EXPOSE 端口映射到物理机的随机端口.
ENTRYPOINT
当定义了ENTRYPOINT之后,CMD只可以做为参数进行传递.
有2种定义方式: 1.ENTRYPOINT ["executable","arg1","arg2"] (推荐) CMD能够经过json的方式来定义entrypoint的参数,在运行容器的时候能够经过CMD的方式传递参数.执行的程序的pid为1. 2.ENTRYPOINT cmd param1 param2 (shell form) 至关于/bin/bash -c "cmd"命令.bash的pid为1.会屏蔽掉docker run时后面加的命令和CMD里的参数.不经常使用.
示例,第一种,好比:
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
把可能须要变更的参数写到CMD里面。而后你能够在docker run里指定参数,这样CMD里的参数(这里是-c)就会被覆盖掉,而ENTRYPOINT里的不会被覆盖。
ENTRYPOINT更像是一个可执行程序,而CMD是随时均可能被覆盖的命令或传参.
COPY & ADD
不建议用ADD.
相似于直接在bash里执行的指令是 docker container cp [containID]:[/path/to/file] /local/path/dir/ (容器文件拷贝到物理机).
把host上的文件或者目录(源文件必须在context路径下)复制到image中.若是目录不存在会在复制文件前先行建立缺失目录.
不建议使用ADD(由于语义模糊,且不必)
ADD相对COPY多的功能(支持URL),当src为网络URL的状况下,ADD指令能够把它下载到dest的指定位置.ADD相对COPY多的功能,可以进行自动解压压缩包.
ENV
ENV
后面的其它指令,如 RUN,仍是运行时的应用,均可以直接使用这里定义的环境变量。
WORKDIR
用来改变工做目录.
好比:
RUN cd /app
RUN echo "hello" > world.txt
这样作根本不会生成/app/world.txt文件.缘由是,每个 RUN 都是启动一个容器、执行命令、而后提交存储层文件变动。第一层 RUN cd /app 的执行仅仅是当前进程的工做目录变动,一个内存上的变化而已,其结果不会形成任何文件变动。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更彻底不要紧,天然不可能继承前一层构建过程当中的内存变化。
所以若是须要改变之后各层的工做目录的位置,那么应该使用 WORKDIR 指令。
USER
改变以后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份.
扩展知识: 若是以 root 执行的脚本,在执行期间但愿改变身份,好比但愿以某个已经创建好的用户来运行某个服务进程,不要使用 su 或者 sudo,这些都须要比较麻烦的配置,并且在 TTY 缺失的环境下常常出错。建议使用 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" ] #exec的说明,执行shell脚本三种方式的区别( sh,bash,xxx.sh / source,. / exec ) 见<<shell bash 技巧说明>>笔记.
VOLUME
Dockerfile中的VOLUME使每次运行一个新的container时,都会为其自动建立一个匿名的volume,并挂载到container指定的目录里.
应用场景: 用来建立一个在image以外的mount point,能够用来在多个container之间实现数据共享(经过--volumes-from吗?).
运行使用json array的方式定义多个volume.
VOLUME ["/var/data1","/var/data2"] .
或者plain text的状况下定义多个VOLUME指令.
示例,cat Dockerfile
FROM nginx #VOLUME ["/home/admin/test"] 或 #VOLUME ["/home/admin/test","home/admin/mynginx"] 或 VOLUME /home/admin/test 在docker container run xxx 的时候,会建立一个匿名volume.好比,物理机上的/var/lib/docker/volumes/99b2...d1/_data -> 容器内的/home/admin/test .
在 Dockerfile 中添加数据卷
在 Dockerfile 中咱们可使用 VOLUME 指令向容器添加数据卷:
VOLUME /data # 这里只跟容器有关,由于为了匹配不一样物理机卷环境,因此物理机卷必是匿名卷.
在使用 docker build 命令生成镜像而且以该镜像启动容器时会挂载一个主机数据卷到容器 /data 目录。根据咱们已知的数据覆盖规则,若是镜像中存在 /data 目录,镜像中的/data目录的内容将所有被复制到宿主机中对应的目录中(匿名目录),而且根据容器中的文件设置合适的权限和全部者。假设在docker run 的时候,添加 -v /data:/data(前一个是物理主机目录,且有数据,后一个是新启动容器目录) ,会发生什么呢?应该会以物理机数据优先吧.
注意,VOLUME 指令不能挂载主机中指定的目录。这是为了保证 Dockerfile 的一致性,由于不能保证全部的宿主机都有对应的目录。
在实际的使用中,这里还有一个陷阱须要你们注意:在 Dockerfile 中使用 VOLUME 指令以后的代码,若是尝试对这个数据卷进行修改,这些修改都不会生效!下面是一个这样的例子:
FROM ubuntu RUN useradd nick VOLUME /data # 其实把VOLUME当作声明就能够了,不实际建立卷.这样理解. RUN touch /data/test.txt RUN chown -R nick:nick /data
经过这个 Dockerfile 建立镜像并启动容器后,该容器中存在用户 nick,而且可以看到 /data 目录挂载的数据卷。可是 /data 目录内并无文件 test.txt,更别说 test.txt 文件的全部者属性了。要解释这个现象须要咱们了解经过 Dockerfile 建立镜像的过程:
Dockerfile 中除了 FROM 指令的每一行都是基于上一行生成的临时镜像运行一个容器,执行一条指令并执行相似 docker commit 的命令获得一个新的镜像。这条相似 docker commit 的命令不会对挂载的数据卷进行保存。
因此上面的 Dockerfile 最后两行执行时,都会在一个临时的容器上挂载 /data,并对这个临时的数据卷进行操做,可是这一行指令执行并提交后,这个临时的数据卷并无被保存。于是咱们最终经过镜像建立的容器所挂载的数据卷是没有被最后两条指令操做过的。咱们姑且叫它 "Dockerfile 中数据卷的初始化问题"。
下面的写法能够解决 Dockerfile 中数据卷的初始化问题:
FROM ubuntu RUN useradd nick RUN mkdir /data && touch /data/test.txt # 建立了/data目录 RUN chown -R nick:nick /data VOLUME /data # 在声明前,镜像里已经有/data目录了,那么会将目录以及内容复制到启动的容器匿名目录里(对应容器的/data目录).
经过这个 Dockerfile 建立镜像并启动容器后,数据卷的初始化是符合预期的。这是因为在挂载数据卷时,/data 已经存在,/data 中的文件以及它们的权限和全部者设置会被复制到数据卷中(被复制到物理主机的匿名卷中,对应的就是新启动的容器的/data目录)。
还有另一种方法能够解决 Dockerfile 中数据卷的初始化问题。就是利用 CMD 指令和 ENTRYPOINT 指令的执行特色:与 RUN 指令在镜像构建过程当中执行不一样,CMD 指令和 ENTRYPOINT 指令是在容器启动时执行。所以使用下面的 Dockerfile 也能够达到对数据卷的初始化目的:
FROM ubuntu RUN useradd nick VOLUME /data CMD touch /data/test.txt && chown -R nick:nick /data && /bin/bash
HEALTHCHECK
健康检查
ONBUILD:略
如何编写最佳的Dockerfile(基本为网上内容)
目标:
总结(编写Dockerfile须要注意的问题)
示例
最初示例
示例Dockerfile犯了几乎全部的错.假设咱们须要使用Docker运行一个Node.js应用,下面就是它的Dockerfile(CMD指令太复杂了,因此我简化了,它是错误的,仅供参考)。
FROM ubuntu ADD . /app RUN apt-get update RUN apt-get upgrade -y RUN apt-get install -y nodejs ssh mysql RUN cd /app && npm install # this should start three processes, mysql and ssh # in the background and node app in foreground # isn't it beautifully terrible? <3 CMD mysql & sshd & npm start #这里是错误的
构建镜像:
docker build -t wtf .
这里先给出最终示例(对比):
FROM node:7-alpine ENV PROJECT_DIR=/app WORKDIR $PROJECT_DIR COPY package.json $PROJECT_DIR RUN npm install COPY . $PROJECT_DIR ENV MEDIA_DIR=/media \ NODE_ENV=production \ APP_PORT=3000 VOLUME $MEDIA_DIR EXPOSE $APP_PORT ENTRYPOINT ["./entrypoint.sh"] CMD ["start"]
将最初示例逐步进行优化的过程
编写.dockerignore文件
构建镜像时,Docker须要先准备context ,将全部须要的文件收集到进程中。默认的context包含Dockerfile目录中的全部文件,可是实际上,咱们并不须要.git目录,node_modules目录等内容。示例以下:
.git/
node_modules/
FROM ubuntu ADD . /app RUN apt-get update RUN apt-get upgrade -y # we should remove ssh and mysql, and use # separate container for database RUN apt-get install -y nodejs # ssh mysql RUN cd /app && npm install CMD npm start
将多个RUN指令合并为一个
Docker镜像是分层的.Docker镜像相似于洋葱。它们都有不少层。为了修改内层,则须要将外面的层都删掉。记住这一点的话,其余内容就很好理解了。
如今,咱们将全部的RUN指令合并为一个。
记住一点,咱们只能将变化频率同样的指令合并在一块儿。将node.js安装与npm模块安装放在一块儿的话,则每次修改源代码,都须要从新安装node.js,这显然不合适.
基础镜像的标签不要用latest
当镜像没有指定标签时,将默认使用latest 标签。当镜像更新时,latest标签会指向不一样的镜像,这时构建镜像有可能失败。
示例Dockerfile应该使用16.04做为标签。
FROM ubuntu:16.04 RUN apt-get update \ && apt-get install -y nodejs \ # added lines && rm -rf /var/lib/apt/lists/* ADD . /app RUN cd /app && npm install CMD npm start
FROM node:7-alpine ADD . /app RUN cd /app && npm install CMD npm start
FROM node:7-alpine WORKDIR /app ADD . /app RUN npm install CMD ["npm", "start"]
FROM node:7-alpine WORKDIR /app ADD . /app RUN npm install ENTRYPOINT ["./entrypoint.sh"] #该脚本能够接受dev,start,*等参数. CMD ["start"] 可使用以下命令运行该镜像: # 运行开发版本 docker run our-app dev # 运行生产版本 docker run our-app start # 运行bash版本 docker run -it our-app /bin/bash
在entrypoint脚本中使用exec
在前文的entrypoint脚本中,我使用了exec命令运行node应用。不使用exec的话,咱们则不能顺利地关闭容器,由于SIGTERM信号会被bash脚本进程吞没。exec命令启动的进程能够取代脚本进程,所以全部的信号都会正常工做。
FROM node:7-alpine WORKDIR /app COPY . /app RUN npm install ENTRYPOINT ["./entrypoint.sh"] CMD ["start"]
FROM node:7-alpine WORKDIR /app COPY package.json /app RUN npm install COPY . /app ENTRYPOINT ["./entrypoint.sh"] CMD ["start"]
FROM node:7-alpine ENV PROJECT_DIR=/app WORKDIR $PROJECT_DIR COPY package.json $PROJECT_DIR RUN npm install COPY . $PROJECT_DIR ENV MEDIA_DIR=/media \ NODE_ENV=production \ APP_PORT=3000 VOLUME $MEDIA_DIR EXPOSE $APP_PORT ENTRYPOINT ["./entrypoint.sh"] CMD ["start"]
ENV指令指定的环境变量在容器中可使用。若是你只是须要指定构建镜像时的变量,你可使用ARG指令。
使用LABEL设置镜像元数据
使用LABEL指令,能够为镜像设置元数据,例如镜像建立者或者镜像说明。
旧版的Dockerfile语法使用MAINTAINER指令指定镜像建立者,可是它已经被弃用了。
有时,一些外部程序须要用到镜像的元数据,例如nvidia-docker须要用到com.nvidia.volumes.needed。
示例以下:
FROM node:7-alpine
LABEL maintainer "jakub.skalecki@example.com"
...
FROM node:7-alpine LABEL maintainer "jakub.skalecki@example.com" ... EXPOSE $APP_PORT HEALTHCHECK CMD curl --fail http://localhost:$APP_PORT || exit 1 ENTRYPOINT ["./entrypoint.sh"] CMD ["start"]
当请求失败时,curl --fail 命令返回非0状态。
20180728 Chenxin
Docker是容器技术的核心、基础.
Docker Compose是一个基于Docker的单主机容器编排工具,功能并不像Docker Swarm和Kubernetes是基于Dcoker的跨主机的容器管理平台那么丰富。
这个也挺经常使用的,将一组服务的多个docker一块儿管理.具体须要深刻研究
你说多服务?好吧那就写个docker-compose.file吧。 嗯哼? 你说集群部署 来来来, 有Kubernetes、Mesos,Fleet和Swarm 任君挑选
https://docs.docker.com/compose/
https://blog.csdn.net/pushiqiang/article/details/78682323
https://www.cnblogs.com/neptunemoon/p/6512121.html
Compose 中有两个重要的概念:
服务 (service):一个应用的容器,实际上能够包括若干运行相同镜像的容器实例。
项目 (project):由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。
Compose 的默认管理对象是项目,经过子命令对项目中的一组容器进行便捷地生命周期管理。
安装: pip install docker-compose 若是报错,添加参数 --ignore-installed docker-compose