Docker学习笔记
什么是Docker
docker是什么
docker 是一种让容器(container)在主机(host)能运行的一种技术,主要包括容器规范、容器runtime、容器定义/管理工具、Register以及容器OS
docker管理工具
规范:Open Container Initiative(OCI)发布了两个规范:runtime spec和image for mat spec。保证在不同镜像可以在不同的runtime上面正常运行。
runtime: 容器的运行环境,主流的包括runc、lxc、rkt,其中runc是Docker自己开发的。
容器管理工具:runc对应的是docker engine,其中包括了 deamon和cli;lxc对应的是lxd;rkt对应的是rkt cli。
容器定义工具:docker image是Docker容器的模板,dockerfile是包含若干命令的文本文件,ACI(App Container Image)与docker image类似,但是是centos开发的。
Registry: Registry保管镜像就有点像git来管理代码。Docker Hub是Docker的官方Registry,Quay.io是另一个。当然也可以利用Docker Registry自建。
容器OS:专门运行容器的系统,优势是比其他系统更小,比如CoreOS、Atomic和Ubuntu Core。
docker是基于主机Host的系统内核,所以更加轻便,而虚拟机则是完全模拟出一个系统环境,更粗暴的理解从系统层面来看,虚拟机就是一个完全独立的“国家”,而docker环境就有点像半殖民地的样子。
docker镜像
镜像结构
镜像层次可以分为核心层(kernal)、镜像层和容器层(其中容器层是可写入的状态)。docker有个重要的特性就是:Copy-on-Write,也就是变更出现只会出现在容器层,不会变更到镜像层。在容器层面添加文件,文件只会保留在容器层;读取是在从上到下层读,直到读取文件写入内存;修改文件:从镜像层查找到文件后复制到容器层,然后修改;删除也不是直接删掉镜像里面的文件,而是在容器层记录这个删除动作而已。
构建方式
docker构建方式分两种,一种是从已经在运行的容器中打包(commit)成镜像,一种是通过Dockerfile来实现。
- docker commit [容器名] [新镜像名]
复制代码 build是借助Dockerfile来完成构造:.表示build context,我们可以用-f来表明dockerfile所在位置,不然就会默认在build context找。其本质就是每执行一条指令,生成一个容器然后commit成新的镜像层。缓存特性:
docker镜像生成是一层层叠加的,为了提升生成速度,docker会缓存已有镜像的镜像层,构建新镜像时,如果镜像已经存在就会直接使用,无须重新创建。如果不希望使用缓存,可以使用--no-cache参数。Dockerfile中每一个指令都会创建一个镜像层,上层是依赖下层的,所以如果上面的语句发生变化,那么下面的缓存都会失败。
docker的Dockerfile常用指令:
- FROM:指定默认镜像,每个Dockerfile必须包含的指令,如果确实没有默认的镜像可以用scratch
- MAINTAINER:设置镜像作者,可以任意字符串
- COPY:将文件从build contxtx复制到镜像
- ADD:与COPY类似,但是它会自动解压压缩文件(tar\zip\tgx\xz等)
- ENV:设置环境变量
- EXPOSE:指定容器监听某个端口,Docker可以将该端口暴露出来。
- VOLUME:将文件或目录声明为volume,把目录下文件打包进镜像。
- WORKDIR:切换当前工作目录,为RUN\CMD\ENTRYPOINT\ADD或者COPY使用。
- RUN:在容器指令命令
- CMD:容器启动且docker没有指定其他运行指令,只最后一个生效
- ENTRYPOINT:容器启动时运行的命令,但是只有最后一个生效,CMD或者run 之后的参数会被当成参数传递给ENTRYPOINT。
三、RUN/CMD/ENTRYPOINT区别
在docker有两种命令运行方式:shell和exec。
shell格式:如run apt-get install python,通常run使用这种格式
exec:["executable", "param1", "param2"]如run ["apt-get", "install", "python"]。通常CMD和ENTRYPOINT推荐这种格式。
但是要注意一点,指令执行时,会直接调用[COMMAND],不会进行shell解析。比如ENV name Docker ENTRYPOINT ["/bin/echo", "Hello, $name"],name是不会被替换的,你需要改成ENV name Docker ENTRYPOINT ["/bin/sh", "-c","echo Hello, $name"]
指令多个指令是否会被覆盖格式推荐使用场景run否exec和cmd都支持构建镜像安装应用鹅软件包CMD是除了支持exec和cmd,还支持cmd ['param1', 'param2']格式来给ENTRYPOINT传参,但是ENTRYPOINT必须使用exec格式。通用我们运行run -it时候后面参数就是这样传递。容器默认启动命令,可以使用CMDENTRYPOINT是exec和cmd都支持,但是如果使用CMD传参就必须用exec格式。
ENTRYPOINT ['"bin/echo","hello" ] CMD ["world"]docker运用程序或服务,如运行一个Mysql,可以优先使用exec格式,用CMD传参,后面可以被run命令替换特定镜像的名字由两部分组成:[repository]:[tag]。如果在build时候没有加tag,那么默认latest。可以通过docker tage [镜像名] [新镜像名]来打tag。
如果要上传自己的镜像到docker hub,镜像中的repository包含,格式如下 :registry:[username]/xxx:tag,接着使用docker push就可以推送。
docker窗口
容器的创建运行
运行指令:docker run -it [镜像名] [command] -it 表示终端交互,-d后端运行, --name显示给容器命名, --restart=always总是表示自动重启,也可以填非零整数,表示最多重启次数。
容器的相关操作
- 进入容器:有两种方式,一种是通过docker attach,一个是通过docker exec 后面跟容器短ID\长ID或者容器名字。attach是不会启动新的进程,但是exec是打开新的终端,如果想看启动命令就需要用attach,也可以用docker logs。attach 可通过Ctrl+p然后加Ctrl+q组合退出attach终端,在exec退出用exit。
- 查询运行容器:docker ps
- 停止容器:docker stop [containerID] docker stop其实是向进程发送一个SIGTERM信号,如果想快速,可以使用docker kill命令。
- 启动容器:docker start [containerID],启动之前停止的容器
- 重启容器:docker restart [containerID],相当于先stop再start。
- 暂停容器:docker pause [containerID]
- 恢复容器:docker unpause [containerID]
- 删除容器:docker rm [containerID],rm可以一次性删除多个
容器资源限制:
对于容器,Docker也提供类似资源限制参数
- 内存: -m或者--memory是直接限制内存,--memory-swap为内存+swap限制
- 处理器:-c或者--cpu-shares设置权重,这里要注意的是,这里的值不代表绝对数量,只是一个权重值。
- BlockIO带宽限额:BlockIO指磁盘的读写,可以通过权重、限制bps和iops的方式控制容器读写带宽。--blkio-weight改变容器block IO优先级,默认500。也可以直接限制读写速度:--device-read/write-bps/iops
Docker网络
在创建容器时,有个参数network来管理docker的网络配置。
None网络
如果在创建中直接使用了--network=none,表示完全封闭的网络,这种对于需要高安全性且不需要联网的服务有用。
Host网络
如果在创建中直接使用了--network=host,表示使用host网络,直接使用host的网络好处是如果窗口对网络传输效率有较高要求的话,性能会比较好,但是可能就会出现端口冲突问题了。
Bridge网络
bridge是network默认选项,用的是veth pair技术,类似用一根虚拟网络连接一对网卡,网卡一头连容器,一头连网桥。
自定义user-defined网络
用户可以自定义网络,三种网络驱动包括:bridge、overlay和macvlan。创建方法是先用docker network 创建:docker network create --driver [driver name] [network name],然后在network参数直接用新建的就可以。
容器通信
容器间想要通信有以下几种方式:
- IP通信,在一个网络的网卡就可以
- Docker DNS Server:仅限user-defined有效。
- joined容器,第二个想跟第一个容器通信的话,可以在network=container:[containername]
容器默认可以与外界通讯的原因是因为MASQUERADE通过用户NAT网络地址转换来做了一层处理。而外部访问容器则是使用docerk-proxy。
Docker存储
正是docker storage driver实现了多层数据的堆叠并为用户提供了一个单一合并视图。
Data Volume
docker volume本质是Docker Host文件系统中的目录或者文件,能够直接被挂在容器的文件系统中。data volume是目录或者文件,容器可以直接读写里面的数据,而容器被删它也存在。
docker提供两种类型的volumen: bind mount和docker managed volume。
bind mount是在运行容器时-v ::
docker manage volume与bind mount使用不同的点是不需要指明挂在容器的哪个位置,-v ,因为容器申请时会在/var/lib/docker/volumes下生成一个目录,可以通过docker inspect containerID 或者 docker volume查找(后续可以使用docker volume rm 来删除)。需要注意的是,使用这种方式会把host的文件传到volume。
volumn container
多容器共享数据的问题,一种简单的方式就是都用bind mount的方式绑定同一个目录,但是这个很麻烦,所以提供了volumn container的方法:
- 首先创建一个容器:docker create --name vc_data -V [hostpath]:[containerpath] -v [image]
- 在其他容器启动时加 --volumes-from vc_data 就可以了。
实战
搭建一个自己Python的Jupyter notebook环境:
获得PIP安装包:- pip freeze > requirements.txt
复制代码 Dockerfile:- FROM python:3
- WORKDIR /usr/src/app
- COPY requirements.txt ./
- RUN pip install --no-cache-dir -r requirements.txt
复制代码 运行build:- docker build -t jupyternotebook-934 .
复制代码 执行:- docker run -it -rm -p 8888:8888 \
- jupyternotebook-934 \
- jupyter notebook \
- --ip=0.0.0.0 --port=8888 --no-browser \
- --allow-root
复制代码 来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |