安装

Linux系统下安装

wget -qO- https://get.docker.com/ | sh

如果需要使用非root用户管理docker(最佳实践),需要添加用户到docker组:

sudo usermod -aG docker your-user
# 查看用户组:
# cat /etc/group | grep docker

添加后注意先注销再登录。

  • 查看版本信息:docker --version
  • 升级Docker引擎(Ubuntu系统下操作)
    # 1.停止Docker daemon,更新安装包列表
    apt-get update 
    # 2. 卸载Docker(docker可能有不同的名称,尽量列出可能的名称)
    apt-get remove docker docker-engine docker-ce docker.io -y
    # 3. 安装新的版本
    wget -qO- https://get.docker.com/ | sh 
    # 4. 设置开机自启
    systemctl enable docker 
    # 5. 检查Docker状态
    systemctl is-enabled docker 
    # 6. 确保容器和服务已经重启
    docker container ls
    docker service ls
    
  • Docker和存储驱动 Linux系统下的Docker存储驱动有以下四种:
    • aufs (the original and oldest)
    • overlay2 (probably the best choice for the future)
    • devicemapper
    • btrfs
    • zfs
    # 备注:windows下只支持 windowsfilter 驱动
    
    一个Docker主机只能有一种存储驱动(不能每个容器一种驱动),可以通过docker info查看当前存储驱动。

Windows10下安装

  • 设置>程序和功能>启用或关闭Windows功能窗口中开启ContainersHyper-V
  • https://docs.docker.com/docker-for-windows/install/ 下载Docker For Windows进行安装
  • 注意到安装完之后会让你选择原生Windows容器还是Linux容器,即容器的运行主机环境,一般选Linux容器(可自由切换)。在Windows下运行Linux容器,是通过Hyper-V虚拟技术来实现的。(目前还没有原生Mac容器)
  • Docker for Windows 包含了: Docker Engine (client 和 daemon),Docker Compose,Docker Machine 和 the Docker Notary command line

镜像(Image)

将镜像类比于编程语言中的类,那么容器就相当于类的实例。

  • 镜像的基本操作
    • 拉取:docker image pull <repository>/<name>:<tag>,默认为镜像的latest tag, 加-a选项将会拉取镜像的所有tags。对于官方镜像,不用声明repository
    • 查看:docker image ls,加--digests输出摘要信息,加--filter过滤输出结果
    • 输出详细信息:docker image inspect xxx
    • 删除:docker image rm xxx
    • 删除所有:docker image rm $(docker image ls -q) -f,其中image ls -q返回所有镜像ID
    • 搜索:docker search xxx
  • 镜像由一组松散的只读层(layer)组成,上层可以覆盖下层,多个镜像可以共享一个层

Docker deep dive

  • 多架构镜像(Multi-architecture images):一个镜像可能需要支持多种架构,比如:Windows,ARM,这时就可以使用多架构镜像( manifest list中记录支持的架构信息)。

容器

容器是镜像的运行时实例。

Docker deep dive

  • Docker版本信息:docker version,如果用户账号没有权限,记得将其添加到Docker组
  • 检查Docker状态:service docker status或者systemctl is-active docker
  • 容器基本操作
    • 开启一个容器:docker container run
      • -it:表示把当前的终端连接到容器的shell,例如: docker container run -it ubuntu /bin/bash,将启动一个Ubuntu容器,然后运行它的Bash Shell。Window容器例子:docker container run -it microsoft/powershell:nanoserver pwsh.exe
      • 启动并连接到bash后,可以ps -elf查看进程详情。输入exit退出bash,容器运行时不能没有进程,如果这时容器没有进程,将会自动退出
      • Ctrl+PQ键退出bash而不会终止容器。
      • --name:设置容器名称,如果没有指定,会自动生成一个
    • 查看:docker container ls,加-a同时输出所有的容器
    • Ctrl+PQ键退出后重新回到容器的bash:docker container exec -it 3027eb644874 bash,其中容器ID值可以先通过docker container ls得到
    • 停止:docker container stop xxx
    • 重启: docker container start xxx
    • 删除: docker container rm xxx
  • 优雅地删除容器:先停止再删除
  • 容器重启策略
    • always 总是重启停止了的容器,除非显式地停止容器(比如通过 docker container stop),例子:docker container run --name neversaydie -it --restart always alpine sh
    • unless-stopped 显式地停止后,重启Docker服务不会再重启
    • on-failed 当容器以非0退出码退出,或者Docker服务重启
  • 在 Docker Compose 或 Docker Stacks中指定重启策略,例子:
    version: "3"
    services:
    myservice:
    <Snip>
    restart_policy:
    condition: always | unless-stopped | on-failure
    
  • Web server 例子
    • 运行 docker container run -d --name webserver -p 80:8080 nigelpoulton/pluralsight-docker-ci
      • -d表示后台运行,前台运行(进入容器交互环境)使用-it
      • -p 80:8080将宿主机80端口映射到容器的8080端口
    • 然后浏览器访问宿主机IP或者curl ip即可打开网页
    • 查看镜像详情:docker image inspect nigelpoulton/pluralsight-docker-ci
  • 清理所有容器:docker container rm $(docker container ls -aq) -f

容器化应用

容器化一个单容器应用

  • 下载应用代码:git clone https://github.com/nigelpoulton/psweb.git
  • 查看其中的Dockerfile文件,代码及注释如下:
    #  All Dockerfiles start with the FROM instruction. This will be the base layer of the image
    FROM alpine
    # 元数据,不构成Layer
    LABEL maintainer="nigelpoulton@hotmail.com"
    # Alpine apk package manager to install nodejs and nodejs-npm into the image.
    RUN apk add --update nodejs nodejs-npm
    # copies in the app files from the build context 
    COPY . /src
    # 元数据,不构成Layer
    WORKDIR /src
    RUN npm install
    # exposes a web service on TCP port 8080
    # 元数据,不构成Layer
    EXPOSE 8080
    # set the main application that the image(container) should run
    ENTRYPOINT ["node", "./app.js"]
    
    以上代码可以生成的镜像示意图: Docker deep dive
  • 构建镜像:docker image build -t web:latest .(最后的(.)号表示构建上下文为当前目录)
  • 查看:docker image ls
  • 推送到Docker Hub
    • 登录:docker login(需先注册账号)
    • 给镜像打标签:docker image tag web:latest nigelpoulton/web:latest,后面的参数形式为:<current-tag> <new-tag>
    • 推送:docker image push nigelpoulton/web:latest
  • 运行应用:
    docker container run -d --name c1 \
    -p 80:8080 \
    web:latest
    
  • 查看应用:docker container ls
  • 测试应用:访问对应的地址
  • 查看镜像的构建历史:docker image history web:latest

使用多阶段构建部署到生产环境

将构建过程分成多个镜像,后面的镜像可以从前面的镜像中拷贝必要的文件,避免镜像体积过大。

Compose

Compose 用于单引擎模式(单个节点)下部署和管理多容器应用。

  • Linux系统下安装:参考https://github.com/docker/compose/releases
  • 查看版本:docker-compose --version
  • 使用yaml格式配置文件,默认文件名为docker-compose.yml-f可以指定自定义文件
  • 配置文件例子
    # 版本,参考:https://docs.docker.com/compose/compose-file/compose-versioning/
    version: "3.5"
    # 服务,以下配置包含服务(容器):web-fe,redis
    services:
    		web-fe:
    			# 使用当前目录的Dockerfile构建镜像
    			build: .
    			# 容器启动时运行(这句可省略,因为Dockerfile已经定义)
    			command: python app.py
    			# 将容器里面的5000端口映射到宿主主机5000端口
    			ports:
    				- target: 5000
    				published: 5000
    			# 指明添加到哪个网络
    			networks:
    				- counter-net
    			# 将卷counter-vol挂载到容器的/code目录
    			volumes:
    				- type: volume
    				source: counter-vol
    				target: /code
    		redis:
    			# 从 redis:alpine 构建镜像
    			image: "redis:alpine"
    			networks:
    				counter-net:
    # 网络
    networks:
    		counter-net:
    # 卷
    volumes:
    		counter-vol:
    
    以上配置可分为四个部分: version、services、networks、volumes
  • 使用Compose进行部署
    • 下载代码:git clone https://github.com/nigelpoulton/counter-app.git
    • 切换到counter-app目录,启动应用:docker-compose up & (加&输出日志)
      • Compose 配置文件默认名称为dockercompose.yml docker-compose.yaml
      • 如果不是这两个名称,可以-f指定
      • -d后台运行
  • 使用Compose管理容器
    • 查看服务(容器) docker-compose ps
    • 列出每个服务的进程:docker-compose top
    • 停止应用:docker-compose stop
    • 停止并删除:docker-compose down
    • 重启:docker-compose restart
    • 删除:docker-compose rm

Docker Swarm

由两部分组成:

  • 安全集群:组织Docker节点成为集群
  • 编排引擎:提供部署和管理的API

组成示意图:

《Docker Deep Dive》阅读笔记(一)

创建一个安全Swarm集群

《Docker Deep Dive》阅读笔记(一)

  • 开放端口
    • 2377/tcp: for secure client-to-swarm communication
    • 7946/tcp and 7946/udp: for control plane gossip
    • 4789/udp: for VXLAN-based overlay networks
  • Swarm mode 和 single-engine mode

《Docker Deep Dive》阅读笔记(一)

  • 在一个single-engine mode Docker宿主主机运行: docker swarm init,节点将转为swarm mode,并创建一个新的swarm,该节点则成为第一个manager
  • 其他节点可以加入成为worker或manager
  • 例子(创建一个Swarm,manager:mgr1-mgr3,worker:wrk1-wrk3)
    • 登录 mgr1主机,初始化一个Swarm:

      docker swarm init \
      --advertise-addr 10.0.0.1:2377 \ #其他节点连接该管理者节点的IP和端口
      --listen-addr 10.0.0.1:2377 # 需要监听的IP和端口,一般和上面的一样
      
    • 查看节点:docker node ls

    • mgr1运行:docker swarm join-token manager 生成添加manager节点的命令(包含token) 输出结果大概是这样的:

      To add a manager to this swarm, run the following command:
      docker swarm join \
      --token SWMTKN-1-0uahebax...ue4hv6ps3p \
      10.0.0.1:2377
      

      同理,将命令中的manager替换成worker,则生成添加worker节点的命令

    • 添加一个worker节点:登录到wkr1,运行:

      docker swarm join \
      --token SWMTKN-1-0uahebax...c87tu8dx2c \
      10.0.0.1:2377 \
      --advertise-addr 10.0.0.4:2377 \
      --listen-addr 10.0.0.4:2377
      

      该节点将被添加到Swarm作为worker

    • 同理可添加wrk2、wrk3节点

    • 添加一个manager节点:登录到mgr2,运行:

      docker swarm join \
      --token SWMTKN-1-0uahebax...ue4hv6ps3p \
      10.0.0.1:2377 \
      --advertise-addr 10.0.0.2:2377 \
      --listen-addr 10.0.0.1:2377
      

      同理可添加mgr3管理节点

    • 再次查看

      ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
      0g4rl...babl8 * mgr2 Ready Active Reachable
      2xlti...l0nyp mgr3 Ready Active Reachable
      8yv0b...wmr67 wrk1 Ready Active
      9mzwf...e4m4n wrk3 Ready Active
      d21ly...9qzkx mgr1 Ready Active Leader
      e62gf...l5wt6 wrk2 Ready Active
      
      • (*)号代表当前运行命令的节点

Swarm manager高可用

  • Swarm manager原生支持高可用
  • active状态的manager称为Leader,它负责分发任务,转发其他manager的任务,示意图:

《Docker Deep Dive》阅读笔记(一)

  • 管理节点集群之间的内部管理协调使用了Raft共识算法,这样就保证了管理节点高可用(HA
  • 最佳实践:
    • 部署奇数数量的manager(减少split-brain)
    • 不要部署太多manager(3-5个为佳)
  • Swarm内置的安全防护:CA settings, join tokens, mutual TLS, encrypted cluster store,encrypted networks, cryptographic node ID’s等
  • 锁定Swarm
    • 重启旧的manager,恢复旧的备份等操作可能会引起安全问题或者擦除当前的配置
    • 初始化的时候添加--autolock=true
    • 或者对于已有的Swarm更新:docker swarm update --autolock=true,注意保存生成的key,manager重启时候解锁用
    • 重启其中一个Docker节点:service docker restart,看是否能自动添加到集群
    • 查看集群中的节点:docker node ls(会有报错,提示需要解锁)
    • docker swarm unlock解锁,输入KEY

Swarm services

  • 创建,例子:docker service create --name web-fe -p 8080:8080 --replicas 5 nigelpoulton/pluralsight-docker-ci
    • 声明一个服务,名称为web-fe
    • 每个Swarm节点的8080端口映射到服务副本的8080端口
    • --replicas 5表示创建5个服务副本
    • 按回车后,manager作为leader初始化5个副本,每个manager和worker拉取镜像并启动一个容器,跑在8080端口上。leader还要确保服务的要求状态保存在集群上并复制到Swarm的每一个manager。
    • 所有服务都会被Swarm监控着,如果跟要求的状态不符,Swarm将会采取行动,恢复要求的状态。
    • 比如,有一个副本挂掉了,Docker会重新启动一个副本,使其恢复到要求的状态
  • 查看服务:docker service ls(如果在创建服务后马上查看,可能会查看不到,需要等到部署完成)
  • 查看服务副本列表: docker service ps <service-name or serviceid>
  • 详情:docker service inspect xxx
  • 服务的两种模式:
    • replicated(默认):指定副本数量,并尽可能平均分布到集群上
    • global:在每个符合条件的节点上启动一个副本,创建是加--mode global
  • 伸缩一个服务
    • 比如,流量暴增,需要增加服务副本,可以:docker service scale web-fe=10,增加到10个副本
    • docker service ls查看服务,docker service ps查看所有副本情况
    • docker service scale web-fe=5将副本数改回5个
  • 移除服务: docker service rm web-fe
  • 滚动更新
    • 假设镜像需要从v1更新到v2,例子:
      docker service update \
      --image nigelpoulton/tu-demo:v2 \
      --update-parallelism 2 \  # 每次并发更新两个副本
      --update-delay 20s uber-svc   # 20秒延迟
      
  • 问题排除
    • 查看Swarm service日志:docker service logs <service-name>,默认日志驱动为json-file json-filejournald均支持该命令查看