Getting Start

Docker的作用

  • 操作系统虚拟化
  • 充分利用服务器资源
  • 构建云计算PAAS服务

Docker的优点

  • 隔离性,推荐一个Docker容器运行一个服务
    1. 系统资源隔离,软件依赖隔离,系统环境隔离
  • 复用性
    1. 发布的不只是软件,而是软件和软件的运行环境,包括软件和依赖的安装和配置
    2. 镜像方便分享复用
  • 保持开发与运维环境一致性
  • 无需关心分布式服务的端口
    1. Docker Networking
    2. 还是需要关心host
  • 轻量,启动快速,资源消耗小
  • 简单,上手快

安装Docker

启动/停止

  • service docker start/stop/status/info
    1. 启动docker守护进程

非root用户省去sudo执行docker

  • cat /etc/group : 查看docker用户组,如果没有则创建
  • usermod -aG docker usr : 将用户加入组
  • sudo service docker restart : 重启docker engin
  • sudo chmod 777 /var/run/docker.sock : 给套接字附权限

docker设置

  • docker镜像,容器和容器配置在/var/lib/docker下
  • docker容器在/var/lib/docker/containers下
  • 设置链接远程Docker Engin
    1. export DOCKER_HOST=tcp://server-host:2375
    2. 修改文件/etc/docker/daemon.json的host
  • 设置docker registry
    1. 在/etc/docker/daemon.json文件中添加

Docker容器

docker容器操作

  • docker run --name hello -i -t ubuntu /bin/bash

    1. 创建并启动一个名字叫hello的交互式的ubuntu容器
    2. exit退出交互式界面,容器会停止
    3. -d : 创建并启动一个daemon容器,要求容器程序不会终止
    4. -h : 指定容器的host名字
    5. --restart=always : docker会自动重启以外停止的容器
      1. stop/kill的容器不会自动重启
      2. --restart=onfailure:5 : 停止代码为非0才会自动重启,5代表最多重启5次
    6. -p 80: EXPOSE对外公开80端口
      1. docker会随即从宿主机的32768-61000中选择一个端口来连接到80端口
      2. -P对外公开所有EXPOSE的端口
      3. 也可以指定特定端口连接到80端口 -p 8080:80
      4. -p 127.0.0.1:8080:80指定特定网络接口
      5. docker port container_name 80 :查看连接到80端口的端口
    7. --expose : 指定对外部公开EXPOSE指令中的某个端口
    8. --privileged
      1. 特权模式启动容器,使得容器具有几乎所有宿主机的能力,包括一些内核特性和设备访问
      2. 这种模式可以使我们在docker中运行docker
      3. 具有一定安全风险
    9. --cidfile=/tmp/cid.txt : 保存容器id到文件
    10. --volumes-from : 把指定容器的所有卷都加到当前容器
    11. --rm : 运行完毕删除容器
    12. -v :设置卷
  • docker ps

    1. 查看当前正在运行的容器
    2. -a : 查看所有容器
    3. -n 10 : 查看最后10个容器
    4. --no-trunc : 不使用缩略
  • docker create/start/stop/kill/restart/rm container_name

    1. 创建/启动/停止/立即停止/重启/删除容器
    2. 启动会沿用创建时的command
    3. docker rm `docker ps -a -q`: 删除所有容器
    4. docker kill -s signal container : 这个操作是发送信号而不是杀掉容器
  • docker attach container_name

    1. 启动后可以根据容器的command重新附着到容器
  • docker exec -d container_name shell_script

    1. 在容器内部添加一个daemon进程
    2. -u 给进程设置用户
    3. docker exec -i -t container_name /bin/bash : 添加一个交互式窗口
  • docker wait container_name : 阻塞直到容器命令执行完成,并返回返回码

  • docker container prune : 删除所有停止到容器

Docker容器查询

  • docker logs
    1. 查看容器日志,默认日志驱动json-file,新的日志驱动在不断增加
    2. -f : 实时监控日志,但是之前的日志也会全量显示
    3. --tail 10 : 查看最后10条,--tail 0 -f合用表示不显示旧日志的实时监控
    4. 如果日志没有标准输出,而是输出到文件则无法获取
  • docker top container_name
    1. 查看daemon容器内部的进程
  • docker stats container_1 container_2
    1. 查看多个容器的统计信息,包括CPU/MEM/IO等的使用率
  • docker inspect container_1 container_2
    1. 查看多个容器的全面详细信息
    2. --formate进行信息筛检,支持完整go语言模板,强大
    3. -f "{{range.Mounts}}{{.}}{{end}}" container_name : 查看容器的卷信息

Docker镜像

Dokcer image命令

  • docker images
  • docker image image-name
  • docker pull registry-url/image-name:tag
    1. 不加tag,自动下载latest
    2. 不加registry,从默认registry下载
  • docker search image-name
    1. shot describtion 里的内容会被匹配
  • docker commit : 通过容器创建镜像
    1. 通过基础镜像创建容器
    2. 通过容器创建镜像
      1. docker commit container-name jude/centos:test
      2. jude是镜像的用户名,centos是镜像的仓库名,test是镜像的tag
      3. commit操作只提交容器与基础镜像有差异的部分
  • docker login/logout
  • docker tag image-id new-image-name:tag
  • docker push repository/image:tag
    1. 会自动创建仓库
  • docker rmi image-id

Dockerfile工作原理

  • Dockerfile工作流程
    1. 将构建上下文上传到docker守护进程
    2. FROM指令从基础镜像构建容器,所以第一条指令必须是FROM
    3. 在容器中执行一条指令
    4. 通过docker commit创建新容器的镜像
    5. 通过新创建的镜像运行另一个容器
    6. 执行下一条指令,直到结束
  • build Dockerfile
    1. docker build -f xx -t xx workdir
      1. -t="jude/centos:test" : 指定仓库,镜像名,标签
      2. -f path/file : 指定Dockfile路径
      3. workdir用.表示在当前目录工作
      4. docker build -t jude/image:tag .
    2. .dockerignore
      1. 过滤一些文件,使得不被上传到docker守护进程
    3. 从Git仓库build Dcokerfile
  • Dockerfile构建缓存
    1. Dockerfile的每一步中间镜像都会被存储起来
    2. 下一次构建Dockerfile的时候,会直接发生变化的指令开始
    3. --no-cache不使用缓存,也可以使用时间来打破指令缓存, ENV EDIT_AT 20181003
    4. docker history imageid 查看所有缓存

Dockerfile指令详解

  • FROM/ONBUILD
    1. 基础镜像
    2. ONBUILD RUN ... : 当作为别人的基础镜像时会触发的指令,跟随FROM后运行
    3. 触发器可以有多个,不会被继承
  • RUN
    1. 构建镜像时需要运行的指令
  • ARG
    1. 为docker build指定参数,支持默认值ARG name=jude
    2. docker build --build-arg name=7b
    3. 不要使用ARG传递敏感信息
    4. 预定义参数
      1. HTTP_PROXY/HTTPS_PROXY/FTP_PROXY/NO_PROXY
      2. 也支持全部小写的版本
  • CMD/ENTERPOINT
    1. 容器启动时需要运行的指令
    2. docker run 会覆盖CMD,但是会作为参数传递给ENTERPOINT(--entrypoint会覆盖ENTERPOINT)
    3. 同时使用ENTERPOINT和CMD提供可变参数的带默认值的指令
  • EXPOSE
    1. 用来指定端口,使容器内的应用可以通过端口和外界交互。声明了容器应该打开的端口并没有实际上将它打开
    2. EXPOSE 8080 : 然后再启动容器时使用-P,这样docker会随机从宿主机的32768-61000中选择一个端口来连接到8080端口
    3. EXPOSE要写在最后?
  • WORKDIR
    1. 指定容器的工作目录,CMD/ENTERPOINT在此目录执行
    2. docker run -w覆盖WORKDIR
  • ENV
    1. ENV env_a 1或者ENV a=1 b=2来指定一个或多个环境变量
    2. docker run -e a=b来传递环境变量
    3. RUN命令中通过$env_a来使用,环境变量也会被保存到容器中
  • ADD/COPY
    1. ADD file/url /path/to/file : 将源文件/URL添加到指定目录
    2. 只支持构建上下文中没有ignore的文件
    3. 目的目录不存在,会以755的权限自动创建,UID/GID为0
    4. 如果ADD一个zip文件,会自动解压缩,解压以添加内容,不覆盖原文件的方式进行
    5. ADD会使缓存无效
    6. COPY在守护进程内部执行,而且不会解压缩
  • VOLUME
    1. VOLUME ["/home", "/opt"] : 指定一个或多个卷
    2. 卷的内容可以被容器访问,但是不会被提交到镜像
    3. 多个容器可以共享卷的内容,比如源码文件等
    4. docker run -v 添加/覆盖?卷
    5. 卷可以通过插件支持第三方存储系统,可用于不同宿主机共享卷
    6. 后面加上:ro/:rw来指定容器内目录的读写权限
    7. 利用卷备份数据,Redis备份?
  • USER user:group
    1. 以什么身份启动容器
    2. docker run -u 来覆盖USER
    3. 需要先创建用户:RUN groupadd -r ratesuser && useradd -r citimkts -g ratesuser
  • 其他
    1. MAINTAINER : 作者信息
    2. LABLE a=b c=d
      1. 为镜像添加元数据,比如version,location,type,role
      2. docker inspect jude/image :查看元数据
    3. STOPSIGNAL?

容器间通讯

Docker内部联网

  • docker0
    1. 虚拟以太网桥,ip地址可能是172.17.0.1,用于连接容器和宿主机
    2. 占用B类保留ip的大部分:172.16-172.30
  • veth*/eth0
    1. docker每创建一个容器,就会创建一组互联的网络接口
    2. 其中一端以veth开头,插在宿主机的docker0网桥上面
    3. 另一端是eth0,连接容器内部,ip类似172.17.0.2
  • 通过以上方式创建了虚拟子网,类似一个局域网
    1. 虚拟子网下的容器,除了能链接宿主机的所有ip接口,还能连接与宿主机在同一个局域网的其他机子
  • 内部联网的缺点
    1. 所有应用与容器连接的配置需要硬编码
    2. 重启容器后,容器的ip会改变
    3. 无法与不同宿主机的容器通讯
  • 连接
    1. docker inspect container_name 查看被连接容器的 Networking的IPAddress, ip类似172.17.0.2
    2. 在连接的容器中使用这个局域网地址

通过Docker链接--link来通讯

  • 优点
    1. 无需硬编码
  • 缺点
    1. 无法与不同宿主机的容器通讯
    2. 需要获取env,麻烦
  • 原理
    1. 通过--link获取被联机容器的内部联网的Ip,存储在客户端容器的env里
    2. 可以通过env获取地址
  • 连接
    1. docker run --name redis-name redis : 被连接的容器正常启动,不需要公开端口
    2. docker run --link redis-name:redis-service clinet : 连接的容器可以使用redis-service代替redis的ip

通过公开的端口号通讯

  • 优点
    1. 可以跨越不同宿主机
    2. 如果有服务治理,那么即使同一台宿主机也不需要关心端口号占用
    3. 部署服务时可以不需要关心host,port
  • 缺点
    1. 没有服务治理,连接服务需要关心host:port,需要硬编码,port还有可能变化

Docker Networking

  • 优点

    1. 可以跨越不同宿主机
    2. 通过使用固定port,所有服务都有相同的固定port,无论是否在同一台宿主机
    3. 如果只有一个服务,连host也是固定的,无论在哪台宿主机
    4. 即使是分布式服务,在部署服务时不需要关心host和port
  • 缺点

    1. 如果是分布式服务,连接服务时还是需要关心host,只不过可以根据规则自定义,来模拟服务发现机制
  • 工作原理

    1. 任何一个容器启动,ip信息都会存在容器的/etc/hosts里,重启容器会更新/etc/hosts
    2. 通过解析/etc/hosts,同一个Networing下的容器,都可以ping container-name.network-name连接对方
    3. container-name是唯一的,这个特性制约了分布式的host
    4. 一个容器可以隶属于多个Networking
  • 指令

    1. docker network create/rm network-name
    2. docker network connect/disconnect network-name container-name --alias alias_name
    3. docker run --net network-name --name container-name
    4. 查询
      1. docker network inspect network-name
      2. docker network ls

总结

  • 有服务发现 : Eureka/K8s
    1. 随机端口+随机端口映射
    2. 通过ServiceId映射到宿主机host:port来通讯
    3. 不需要管理host和port
    4. 支持容器间,容器与非容器都通讯
    5. 支持跨宿主机通讯
    6. 不会产生端口冲突
  • 没有服务发现
    1. 同宿主机
      1. docker link
        1. 可以用link name代替ip
        2. 不存在端口冲突问题
    2. 跨宿主机
      1. 端口映射 [本地开发]
        1. 需要hard code对方宿主机都host:port
        2. 无法应对宿主机更改,port修改
        3. 可能存在端口冲突问题
        4. 支持非容器与容器通讯
      2. docker network
        1. 通过--alias通讯
        2. 需要关心port
        3. 不支持非容器与容器通讯
        4. 没有端口冲突
        5. 不支持load balance
  • 本地开发环境使用docker compose,会自动创建docker network,并且公开端口。生产环境使用服务治理。

本地与服务器相互调用

  • Proxy
    1. ssh -CfNg -L 8888:awx-dev-34.awx.im:9999 ubuntu@awx-dev-34.awx.im
    2. 在本地起一个8888端口映射到服务器的9999端口
  • Debug
    1. ssh -CfNg -R 9999:localhost:8888 ubuntu@awx-dev-34.awx.im
    2. 在服务器启动9999端口映射到本地的8888端口
    3. 9999端口只作用在服务器的localhost上,如果需要作用在所有ip段上,需要在/etc/ssh/sshd_config下添加Gateway_Prots yes,然后重启服务器并重新添加监听通道
    4. 实现debug需要服务间用暴露端口的方式调用,而不是docker network调用!!!使用env来将service name调用变为host:port调用
    5. simpleproxy???
  • 其他
    1. 起的端口必须没被占用
    2. 服务的端口需要可以访问,也就是用docker compose暴露端口
    3. 查看和kill ssh端口映射:ps -ef | grep ssh
    4. Debug模式下,kill本地映射进程也会去除服务器的端口映射进程
    5. -i 设置ssh key的路径

Dcoker Build/Deploy

jenkins/maven/docker在宿主机运行

  • 发布image到Regiester
    1. jenkins build
      1. Dockerfile
        1. RUN maven package -> zip
        2. ADD zip -> image
      2. docker push image -> Regiester
    2. jenkins deploy
      1. pull image
      2. run image
  • 在服务器生成image
    1. jenkins build
      1. pom -> zip
      2. Dockerfile -> zip
    2. jenkins deploy
      1. Dockerfile -> image
      2. run image
  • 发布项目文件到VOLUME
    1. 使用以上方法准备空的image和容器
    2. jenkins build
      1. pom-> zip
    3. jenkins deploy
      1. zip -> VOLUME
      2. docker start

jenkins/maven/docker使用docker运行

  • 发布image到Regiester
    1. jenkins build
      1. Dockerfile
        1. RUN maven package -> zip
        2. ADD zip -> image
        3. VOLUME /var/lib/docker
      2. docker push image -> Regiester
    2. jenkins deploy
      1. pull image : VOLUME使得容image会下载到宿主机,而不是docker内部
      2. run image : VOLUME使得容器会运行在宿主机,而不是docker内部
  • 在服务器生成image
    1. 同理使用VOLUME /var/lib/docker
  • 发布项目文件到VOLUME [推荐方案]
    1. 使用以上方法准备空的image或者容器
    2. jenkins所在容器和项目所在容器使用同一个VOLUME

Docker Compose

常用命令

  • docker-compose ps
  • docker-compose pull : 拉去最新的镜像
  • docker-compose up -d :
    1. 以daemon方式创建容器
    2. 同时创建network
  • docker-compose down : 销毁容器和network
  • docker-compose rm : 删除停止的容器
  • docker start: 启动停止的容器

docker-compose.yml

  • image / restart: always / ports: - 80:80 / depends_on:
  • command: [ 'xx' ]
  • container_name : 容器名字,同时也是network里的service id
  • volumes: /home/jude

Docker Swarm