文章目录

  • Devops系统化,从零开始学习Docker、K8s
    • 一、容器技术和Docker简介
      • 1.1 Docker导学
      • 1.2 容器技术概述
    • 二、Docker环境的各种搭建方法
      • 2.1 Docker安装介绍
      • 2.2 在Mac系统上安装Docker
      • 2.3 在Windows系统上安装Docker
      • 2.4 vagrant&irtualBox for Mac
      • 2.5 vagrant&virtualBox for Windows
      • 2.6 在Centos上安装Docker
      • 2.7 Docker Machine的本地使用
      • 2.8 在windows系统下docker-machine的使用
      • 2.9 Docker Machine在亚马逊AWS云上的使用
      • 2.10 Docker Playground
      • 2.11 本章总结
    • 三、Docker的镜像和部署
      • 3.1 Docker架构和底层技术简介
      • 3.2 Docker Image 概述
      • 3.3 DIY一个Base Image
      • 3.4 初始Container
      • 3.5 构建自己的Docker镜像
      • 3.6 Dockerfile语法梳理及最佳实践
      • 3.7 RUN vs CMD vs Entrypoint
      • 3.8 镜像的发布
      • 3.9 Dockerfile实战 - 部署一个python服务
      • 3.10 容器的操作
      • 3.11 Dockerfile实战
      • 3.12 容器的资源限制
    • 四、Docker的网络
      • 4.1 本章概述和实验环境介绍
      • 4.2 网络基础回顾
      • 4.3 Linux网络命名空间
      • 4.4 Docker bridge0详解
      • 4.5 容器之间的link
      • 4.6 容器的端口映射
      • 4.7 容器网络之host和none,及与其他网络各自特点
      • 4.8 Oerlay和Underlay
    • 五、Docker的持久化存储和数据共享
      • 5.1 本章介绍
      • 5.3 数据持久化之Data volume
      • 5.4 数据持久化之Bind Mouting
      • 5.5 开发者利器 - Docker+Bind Mouting
    • 六、Docker Compose多容器部署
      • 6.1 根据前面所学部署一个wordpress
      • 6.2 Docker Compose到底是什么?
      • 6.3 Docker Compose的安装和基本使用
      • 6.4 水平扩展和负载均衡
    • 七、容器编排Docker Swarm
      • 7.1 容器编排Swarm介绍
      • 7.2 创建一个三节点的Swarm集群
      • 7.3 Serice的创建维护和水平扩展
      • 7.4 在swarm集群里通过serice部署wordpress
      • 7.5 集群服务间通信之Routing Mesh
      • 7.6 Routing Mesh 之Ingress 负载均衡
      • 7.7 Docker Stack部署
      • 7.8 Docker Secret管理和使用
      • 7.9 Docker Secret在Stack中的使用
    • 八、Deops初体验 -- Docker Cloud 和Docker企业版
      • 8.1 Docker 的收费模式
      • 8.2 Docker Cloud 简介
      • 8.3 Docker Cloud之自动build Docker image
      • 8.4 Docker Cloud之持续集成和持续部署
      • 8.5 Docker企业版的在线免费体验
      • 8.6 Docker企业版本地安装之UCP
      • 8.7 Docker企业版本地安装之DTR
      • 8.8 Docker企业版UCP的基本使用演示
      • 8.9 体验阿里云的容器服务
      • 8.10 在阿里云上安装Docker企业版
      • 8.11 Docker企业版DTR的基本使用演示
    • 九、容器编排Kubernetes
      • 9.1 Kubernetes简介
      • 9.2 Minikube快速搭建K8s单节点环境
      • 9.3 K8s最小调度单位Pod
      • 9.4 ReplicaSet和ReplicationController
      • 9.5 Deployment
      • 9.6 使用Tectonic在本地搭建多节点k8s集群
      • 9.7 k8s基础网络Cluster Network
      • 9.8 Serice简介和演示
      • 9.9 NodePort 类型Serice以及Label的简单使用
      • 9.10 准备工作---使用kops在亚马逊上搭建k8s集群
      • 9.11 使用kops在亚马逊AWS上搭建k8s集群
      • 9.12 LoadBlancer类型serice以及AWS的DNS服务配置
      • 9.13 在亚马逊k8s集群上部署wordpress
    • 十、Kubernetes简介和安装
      • 10.1 Kubernetes简介
      • 10.2 k8s安装的方法简介
      • 10.3 在windows系统上安装使用minikube
      • 10.4 在Mac系统上安装使用minikube
      • 10.5 使用kubeadm搭建多节点k8s集群
      • 10.6 Google云平台的k8s服务
    • 十一、Kubernetes中的基本概念和操作
      • 11.1 kubectl的基本使用
      • 11.2 k8s的节点和标签
      • 11.3 k8s调度的最小单位pod
      • 11.4 Namespace命名空间
      • 11.5 创建我们自己的context
      • 11.6 Controller 和 Deployment
      • 11.7 deployment的演示
      • 11.8 Replicaset在Deployment更新中的作用
    • 十二、容器的运维和监控
      • 12.1 容器的基本监控
      • 12.2 k8s集群运行资源监控---Heapster+Grafana+InfluxDB
      • 12.3 根据资源占用自动横向伸缩
      • 12.4 k8s集群Log的采集和展示
      • 12.5 k8s集群监控方案Prometheus
    • 十三、Docker+Deops实战 -- 过程和工具
      • 13.1 本章简介
      • 13.2 搭建GitLab服务器
      • 13.3 搭建GitLab CI服务器和Pipeline演示
      • 13.4 简单java项目的CI演示
      • 13.5 CI实现版本自动发布
    • 十四、博文总结

Devops系统化,从零开始学习Docker、K8s

一、容器技术和Docker简介

1.1 Docker导学

  • 到底什么是Docker?

  • Docker能干什么?
  • 容器时代的"双城记"
  • 大海航行靠舵手-Kubernetes
  • DevOps:
    • 它等于: 文化+过程+工具
  • devops执行过程:

1.2 容器技术概述

  • 先聊历史:

    • 购买服务器-> 安装操作系统 -> 安装App

      • 劣势: 1. 部署非常慢 2. 成本非常高 3. 资源浪费 4. 难于迁移和扩展 5. 可能会被限定硬件厂商
    • 虚拟机技术出现后:
      • 一个物理机可以部署多个App
      • 每个App独立运行在一个VM里
      • 图示:
  • 虚拟机的优点:

    1. 资源池 -> 一个物理机的资源分配到了不同的虚拟机里
    2. 很容易扩展 -> 加物理机器 or 加虚拟机
    3. 很容易云化 -> 亚马逊AWS,阿里云等
  • 虚拟机的局限性:

    • 每一个虚拟机都是一个完整的操作系统,要给其分配资源,当虚拟机数量增多时,操作系统本身消耗 的资源势必增多
  • 容器技术为什么会出现?

    • 开发和运维面临的挑战:

      容器被称为“集装箱”,它能够将App进行打包,然后能够用于任何环境,类似于现实中的集装箱。

    • 容器解决了什么问题?
      • 解决了开发和运维之间的矛盾
      • 在开发和运维之间搭建了一个桥梁,是实现devops的最佳解决方案
  • 什么是容器?

    • 图示:
    • 说明:
      1. 对软件和其依赖的标准化打包
      2. 应用之间相互隔离
      3. 共享同一个OS Kernel
      4. 可以运行在很多主流操作系统上
  • 容器和虚拟机的区别?

  • Docker-容器技术的一种实现:

    Docker它是利用了LXC的包装,然后在其基础上开源,成为了一种广泛流行的容器技术,而这种技术不止Docker一种。

二、Docker环境的各种搭建方法

2.1 Docker安装介绍

2.2 在Mac系统上安装Docker

  • 下载界面:
  • 登录:
  • 下载:
  • 启动:

Mac上是一个Unix系统。

2.3 在Windows系统上安装Docker

  • 下载并安装:

  • 点击安装后并重启,然后在Windows桌面打开CMD窗口

    • 输入命令验证Docker是否安装成功:

      docker version
      
    • 出现以下界面说明安装成功:

可能个别同学的不一定能够安装成功,因为每个人的windows环境不是一样的。

2.4 vagrant&irtualBox for Mac

  • 官网:

    • 安装步骤百度。安装成功后,输入“vagrant --help”可以看支持哪些参数。

  • 注意:
    • 我们不要直接在windows上直接上安装Docker,而是应该下载一个虚拟机上安装Docker。因为如果直接下载的话,Docker里面的一些东西会保留在电脑上不容易删除,而使用虚拟机则只需要删除虚拟机即可全部删除。
  • vargrant&virtualBox:
    • VirtualBox 是一款开源虚拟机软件。VirtualBox 是由德国 Innotek 公司开发,由Sun Microsystems公司出品的软件,使用Qt编写,在 Sun 被 Oracle 收购后正式更名成 Oracle VM VirtualBox。
    • Vagrant: Vagrant是一款用于构建及配置虚拟开发环境的软件,主要使用Oracle的开源VirtualBox虚拟化系统,与Chef,Salt,Puppet等环境配置管理软件搭配使用, 可以实行快速虚拟开发环境的构建.

2.5 vagrant&virtualBox for Windows

  • 安装步骤:

    1. 安装VirtualBox
    2. 安装Vagrant
    3. 重启电脑
    4. 打开命令行,然后初始化Vagrant,然后打开virtualBox进行管理
  • 常用命令:
    • 帮助命令:

      vagrant --help
      
    • 运行指定的xxx,以Centos 7 为例:
      vagrant init centos/7
      
    • 运行创建的xxx,以上面为例:
      vagrant up
      
    • 连接创建的xxx,以上面为例:
      vagrant ssh
      
    • 退出:
      exit
      
    • 查看状态:
      vagrant status
      
    • 停止:
      vagrant halt
      
    • 删除:
      vagrant destroy
      

2.6 在Centos上安装Docker

  • 为什么不使用VM ware?

    • 它不是免费的=。=,当然也可以使用!还可以用Hyper-V等工具;
  • 安装步骤:

    1. 准备:

    2. 进入机器:

      vagrant ssh
      
    3. 卸载旧版本Docker:

    4. 安装Repository:

    5. 添加repo:

    6. install docker-ce:

      sudo yum install docker-ce
      
    7. 启动docker:

      sudo systemctl start docker
      
    8. 校验版本:

      sudo docker version
      
    9. 校验是否安装成功-- 运行hello,world:

      sudo docker run hello-world
      

2.7 Docker Machine的本地使用

  • 官网:

  • 介绍:

    • Docker Machine 是一种可以让您在虚拟主机上安装 Docker 的工具,并可以使用 docker-machine 命令来管理主机。
    • Docker Machine 也可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker。
  • 安装命令:

    • Linux:

      $ base=https://github.com/docker/machine/releases/download/v0.16.0 &&curl -L $base/docker-machine-$(uname -s)-$(uname -m) >/tmp/docker-machine &&sudo mv /tmp/docker-machine /usr/local/bin/docker-machine &&chmod +x /usr/local/bin/docker-machine
      
    • MacOs命令:
      $ base=https://github.com/docker/machine/releases/download/v0.16.0 &&curl -L $base/docker-machine-$(uname -s)-$(uname -m) >/usr/local/bin/docker-machine &&chmod +x /usr/local/bin/docker-machine
      
    • Windows命令:
      $ base=https://github.com/docker/machine/releases/download/v0.16.0 &&mkdir -p "$HOME/bin" &&curl -L $base/docker-machine-Windows-x86_64.exe > "$HOME/bin/docker-machine.exe" &&chmod +x "$HOME/bin/docker-machine.exe"
      
  • 常用命令:

    1. 校验docker-machine:

      docker-machine version
      

      一般情况下是跟着一起安装成功的。

    2. 创建机器:
      docker-machine create --driver virtualbox test
      
    3. 查看机器的ip:
      docker-machine ip test
      
    4. 停止机器:
      docker-machine stop test
      
    5. 启动机器:
      docker-machine start test
      
    6. 进入机器:
      docker-machine ssh test
      

2.8 在windows系统下docker-machine的使用

  1. 下载并点击安装:

  2. 配置环境变量(地址为实际安装位置):

  3. 搜索Windows ProwerShell并打开

  4. 输入命令查看是否有反应:

    docker-machine
    

    展示此界面说明安装成功:

  5. 创建一个docker:

    docker-machine create demo1
    

    创建一个docker名为demo1的

  6. 创建一个Linux机器:

    创建好机器后会已经自动创建好docker

2.9 Docker Machine在亚马逊AWS云上的使用

  1. 登录后台界面:

  2. 参考官方教程:

  3. 进入菜单:

  4. 进入Security Credentials:

  5. 查看和创建AccessKey:

  6. 创建:

  7. 拷贝命令并创建:

2.10 Docker Playground

  • 官网:
  • 使用:

需要先创建Docker Id,然后在图二上进行使用。它是一个临时的实例。

2.11 本章总结


三、Docker的镜像和部署

3.1 Docker架构和底层技术简介

  • Docker Platform:

    • Docker提供了一个开发,打包,运行App的平台
    • 把App和底层infrastructure隔离开来
    • 图示:
  • Docker Engine:

  • Docker Architecture:

  • 底层技术支持:

    1. Namespaces: 做隔离pid,net,ipc,mnt,uts
    2. Control groups:做资源限制
    3. Union file systems:Container和Image的分层
  • 实验环境搭建:

    • 文件:
    • 创建并启动命令:

    这个是用来练习的,可以忽略。

3.2 Docker Image 概述

  • 什么是Image?

    1. 文件和meta data的集合(root filesystem)
    2. 分层的,并且每一层都可以添加改变删除文件,成为一个新的image
    3. 不同的image可以共享相同的layer
    4. 不同的image可以共享相同的layer
    5. image本身是read-only的
    6. 图示:
  • 示例:

  • image创建示例:

    1. 自己创造:
    2. 拉取:

      从远处拉取

  • 远程仓库:

    第三方的:

3.3 DIY一个Base Image

  • 不使用sudo命令来使用docker的办法:

    把当前用户添加进groupadd. 如果关闭还是不行,则先exit,再重新连接这个服务器。

  • DIY步骤:
    1. 创建一个“hello”的c语言程序:
    2. 安装gcc和glibc-static:
      sudo yum install gcc
      
      sudu yum install glibc-static
      
    3. 编译写的helloworld:
      gcc -static hello.c -o hello
      
    4. 可以直接运行测试:
      ./hello
      

      打印出:“hello docker”

    5. 创建并编辑dockerFile
      vim Dockerfile
      
    6. Dockerfile内容如下:
      FROM scratch
      ADD hello /
      CMD ["/hello"]
      
    7. 构建build:
      docker build -t anyu/hello-world .
      

      . 表示在当前目录

    8. 构建并查看镜像:
    9. 运行通过dockerfile构建的镜像:
      docker run anyu/hello-world
      

      打印内容: “hello docker”

3.4 初始Container

  • 什么是Container?

    1. 通过Image创建(copy)
    2. 在Image layer之上建立一个Container layer(可读写)
    3. 类比面向对象: 类和实例
    4. Image负责app的存储和分发,Container负责运行app

    Container支持读写,它负责运行App。我们基于镜像运行的程序是一个Container,在里面我们能够创建文件夹、进行创建其他的东西(构建对象),然后能够将它打包成一个新的镜像(类)。

  • 删除Container:

    • 删除集装箱:
    • 删除镜像:
    • 批量删除集装箱:
    • 有条件的删除集装箱:

      docker container ls -aq 等价于 docker container ls -a | awk {‘print$1’} 只是第二个带了个头部CONTAINER标识。

3.5 构建自己的Docker镜像

  • docker的简写:

    • docker container commit => docker commit
    • docker image build => docker build
  • 通过docker commit将container打包成image镜像:
    • 示例命令: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] [flags]
  • 创建方式一: 通过已存在的container打包成新的镜像:
    1. 输入构建命令:

      docker commit anyu tagdemo/image-name
      

      anyu 表示已存在的container 的Name, tagdemo表示新建的镜像的tag, image-name表示镜像的名称。

    2. 存在的缺陷:它是基于我们已有的container构建的,不安全,容易泄露我们自己的信息,我们不提倡。
  • 创建方式二:通过Dockerfile来创建:
    1. 创建Dockerfile:

      vim Dockerfile
      
    2. 编写内容:
      FROM centos
      RUN yum install -y vim
      
    3. 根据Dockerfile在当前目录下构建镜像:
      docker build -t dockername/imagename .
      

      dockername是docker名字,你可以自己设置, imagename是镜像名称,可以自己设置;.这个“点”表示当前目录,说明Dockerfile在执行命令当前目录层级中。

3.6 Dockerfile语法梳理及最佳实践

  • FROM (最开头的语法)

    1. FROM scratch # 制作base image
    2. FROM centos # 使用base image
    3. FROM ubuntu:14.4

    FROM =》尽量使用官方的,保证安全

  • LABEL (描述信息: 包括作者、版本、描述等)

    1. LABEL maintainer = “anyu@gmail.com”
    2. LABEL version = “1.0”
    3. LABEL description = “This is description”

    LEBEL/Metadata 不可少!

  • RUN (运行):

    为了美观,复杂的RUN请用反斜线换行!避免无用分层,合并多条命令成一行!

  • WORKDIR(设置当前目录)

    使用WORKDIR ,不要用RUN cd!尽量使用绝对目录!

  • ADD and COPY (解压缩等):

    大部分情况,COPY优于ADD! ADD除了COPY还有额外功能(解压!)添加远程文件/目录请使用curl或者wget!

  • ENV:

    上面定义,下面引用。这样能够做到统一管理,对于版本等,可以统一设置和修改。

  • VOLUME and EXPOSE

    存储和网络后面单独讲

  • CMD and ENTRYPOINT

    后面单独讲

3.7 RUN vs CMD vs Entrypoint

  • 总体介绍:

    1. RUN: 执行命令并创建新的Image Layer
    2. CMD: 设置容器启动后默认执行的命令和参数
    3. ENTRYPOINT: 设置容器启动时运行的命令

      CMD 和 ENTRYPOINT要注意区分,他们很接近。

  • Shell和Exec格式:

  • 两种格式的Dockerfile:

  • CMD:

    1. 容器启动时默认执行的命令
    2. 如果docker run 指定了其他命令,CMD命令被忽略
    3. 如果定义了多个CMD,只有最后一个会执行
    4. 图示:
  • ENTRYPOINT:

    1. 让容器以应用程序或者服务的形式运行
    2. 不会被忽略,一定会执行
    3. 最佳实践: 写一个shell脚本作为entrypoint
    4. 图示:

3.8 镜像的发布

  • Docker Hub:

    • 它是一个镜像发布的网站,类似于Github,能够使用别人的代码等。
    • 步骤:
      1. 登录:
      2. push 我们要push的镜像:
      3. push完成后,就可以在我们自己的docker hub上看到了:

      分享docker image的话,不如分享Dockerfile,这样能够更安全和有隐私性。我们可以在Docker Hub中链接Github,然后只维护Dockerfile,然后Docker会自动帮我们构建镜像。

  • 搭建一个自己私有的Docker Registry

    1. 启动一个私有的registry:

      docker run -d -p 5000:5000 --restart always --name registry r^Cistry:2
      
    2. 查看是否启动成功:
      docker ps
      
    3. 测试远程访问是否成功:

      telnet 如果没有的话,则通过yum进行安装

    4. 构建并查看是否存在:
    5. 编辑registry内的启动文件:
      sudo vim /lib/systemd/system/docker.service
      
    6. 设置文件内容:

      增加标记处这个代码

    7. 重启docker:
      sudu service docker restart
      
    8. 继续push内容:
      docker push ip:5000/hello-world
      

      hello-world替换为你自己要push的镜像

    9. 通过api查看是否push成功,输入地址: ip:5000/v2/_catalog,如图所示:
    10. 测试删除本地镜像,再从远程私有registry中重新拉取:

3.9 Dockerfile实战 - 部署一个python服务

  1. 编写py代码:
  2. 创建Dockerfile:
    vim Dockerfile
    
  3. 对Dockerfile内编辑内容:
  4. 根据Dockerfile构建:
    docker build -t anyu/flask-hello-world .
    
  5. 查看构建好的镜像是否存在:
    docker image ls
    
  6. 构建docker项目:
    docker run anyu/flask-hello-world
    
  7. 与步骤6一样,选择一个即可。此步骤为改为后台运行,加了-d:
    docker run -d anyu/flask-hello-world
    
  8. 查看是否运行:

3.10 容器的操作

  • 图示:

    进入bash后输入exit退出,container还是会继续运行。如果要container停止,则用docker stop命令,只有停止了的container,才能用删除命令;

  • 对于启动的镜像,我们可以指定一个名字,如果不指定名字则docker会为我们随机分配一个名称;

  • docker查看日志输出:

    docker logs $containerID
    
  • docker查看详细信息(创建时间、参数、详细信息等):

    docker inspect $containerID
    

3.11 Dockerfile实战

  • 使用ubuntu-stress,通过外部命令传入运行Dockerfile
  • 步骤:
    1. 创建Dockerfile:
    2. 运行命令:

    --vm 1 --verbose^C命令在外部启动docker时使用,它替换掉了CMD后面的[]的内容。我们也可以在[]内给一个默认命令。

3.12 容器的资源限制

  • 设置内存大小:

    docker run --memory=200M anyu/ubuntu-stress --vm 1 --verbose
    

    memory是设置内存大小,后面是打印的vm信息;

  • 指定cpu个数:

    docker run --cpu-shares=5 --name=test anyu/ubuntu-stress --cpu 1
    

    按照权重的,权重值越大则CPU占比越高

四、Docker的网络

4.1 本章概述和实验环境介绍

  • Docker Network:

4.2 网络基础回顾

  • 基于数据包的通讯方式:

  • 网络的分层:

  • IP地址和路由:

  • 公有IP和私有IP:

  • 网络地址转换NAT:

  • Ping和telent:

    1. 检查IP的可达性
    2. telnet: 验证服务的可用性:

    先保证ip可达,再保证服务可达。因为服务可达是建立在ip可达的基础上嘚。

  • WIRESHARK: 抓包工具,如图所示:
    -

4.3 Linux网络命名空间

  • 命名空间(Linux namespace)是linux内核针对容器虚拟化映入的一个特性

    • 每个容器都有自己的命名空间,运行在其中的应用都像是在独立的操作系统中运行一样,它保证了容器之间互不影响。
  • Linux 内核提供了6中命名空间:

  • 网络命名空间:

    • 在Linux中,网络命名空间可以被认为是个例的拥有单独网络栈(网卡、路由转发表、iptables)的环境。网络命名空间经常用来隔离设备和服务,只有拥有同样的网络命名空间的设备,才能看到彼此。
  • 查看当前网络接口:

    • 代码:

      ip a
      
    • 图示:
  • 打印指定Docker应用的网络地址:

  • netns常用命令:

  • Linux Network Namespace:

4.4 Docker bridge0详解

  • 列出当前docker上的所有网络:

    sudu docker network ls
    
  • Brige Network:
    • 如何两个进行互相访问:

    • 如何访问外网:

4.5 容器之间的link

  • 概念:

    • docker间常常需要互联或者说通信,比如比如后台程序访问数据库容器,一般是需要ip+端口的形式,然而ip是经常会变化的,docker中采用link来为容器起个名字,以后访问只要名字+端口就行了,这样减少了ip访问下,ip常发生变化而导致的问题;
    • 通过docker的link机制可以通过一个name来和另一个容器通信,link机制方便了容器去发现其它的容器并且可以安全的传递一些连接信息给其它的容器。
  • 使用方式如下:

    1. 运行一个容器,通过 -name 指定一个便于记忆的名字,这个容器被称为source container,也就是要连接的容器。

      docker run --name mysql01 -e MYSQL_ROOT_PASSWORD=123456 -d mysql
      

      上面通过传递环境变量MYSQL_ROOT_PASSWORD=123456,来设置mysql服务的密码为123456.

    2. 运行另外一个容器,并link到上面启动的容器,这个容器被称为received container
      docker run -d --name web --link mysql01:aliasdb nginx
      

      上面通过 --link 连接名为 mysql01 的容器,并为其设置了别名 aliasdb

    完成了上面的两个步骤后,在 nginx 的容器中就可以使用 mysql01 或者 aliasdb 作为连接地址来连接mysql服务,即使容器重启了,地址发生了变化,不会影响两个容器之间的连接。

4.6 容器的端口映射

  • 查看docker相关容器的ip及端口命令:

    sudo docker network inspect bridge
    
  • 将本地端口与docker的端口号进行绑定:
    • 代码:

      sudo docker run --name $name-d -p port:port $dockerName
      
    • 图示:

4.7 容器网络之host和none,及与其他网络各自特点

  • 网络除了bridge外还有host和none:

    Docker 安装时会自动在host上创建三个网络,我们使用docker network ls命令查看。

  • none网络:

    • 顾名思义,none网络就是什么都没有的网络。挂在这个网络下的容器除了1o,没有其他任何网卡。容器创建时,可以通过-network=none指定使用none网络,代码如下:

      docker run -it --network=none busybox
      

      封闭意味着隔离,一些对于安全性要求高的并且不需要联网的应用可以使用none网络,比如某个容器的唯一用途是生成随机密码,就可以放到none网络中避免密码被窃取。

  • host网络:

    • 连接到host网络的容器共享Docker host的网络栈,容器的网络配置与host完全一样。可以通过-network-host制定使用host网络,代码如下:

      docker run -it --network=host busybox
      
    • 在容器中可以看到host的所有网卡,并且连hostmame也是host的。host网络使用场景是什么呢?
      • 直接使用Docker host的网络最大的好处就是性能,如果容器对网络传输效率有较高的要求,则可以选择host网络。
      • 当然不便之处就是牺牲一些灵活性,比如要考虑端口冲突问题,Docker host上已经使用的端口就不能再用了。
      • Docker host的另一个用途是让容器可以直接配置host网络,比如某些跨host的网络解决方案,其本身也是以容器方式进行运行的,这些方案需要对网络进行配置,比如管理iptables。
  • bridge网络:

    • Docker安装时会创建一个命名为docker0的Linux bridge.如果不指定-network,创建的容器默认都会挂到docker0上。
  • user-defined网络:

    • 除了none、host、bridge这三个自动创建的网络,用户也可以根据业务需要创建user-defined网络。
    • Docker提供三种user-defined 网络驱动:bridge、overlay 和macvlan。overlay 和macvlan用于创建跨主机的网络。

4.8 Oerlay和Underlay

  • 什么是Oeray和Underlay?

    • Underlay:显示的物理基础层网络设备。数据中心基础转发架构的网络

      以太网最初设计的时候就是一个分布式的网络架构,没有中心控制节点,网络中的节点通过协议传递学习网络的可达性信息。underlay就是数据中心场景的基础物理设施,保证任何两个点路由可达,其中包含了传统的网络技术。

    • Overlay: 一个基于物理网络之上构建的逻辑网络。

      overlay是在网络技术领域指的是一种网络架构上叠加的虚拟化技术模式,Overlay网络也是一个网络,不过是建立在Underlay网络之上的网络。overlay网络节点通过虚拟或者逻辑链路进行通信,其实现基于ip技术的基础网络为主。Overlay网络技术多种多样,一般采用TRILL、VxLan、GRE、NVGRE等隧道技术。

  • 广义上说:
    • underlay和overlay是互相独立的,其中underlay为overlay提供基础承载;
    • underlya和overlay是相对而言的,谁为对方提供基础网络架构,谁就是underlay,相反另外的一方则为overlay;

      提到overlay是近几年数据中心为网络兴起的概念,但是对于传统网络而言实际上早一些类似概念。

      • 传统网络:l2vpn、l3vpn、qinq、macinmac等隧道技术就是传统的overlay网络技术;
      • 数据中心网络:以vxlan、gre、nvgre、trill等新兴隧道技术为基础构建出来的vpc网络;

五、Docker的持久化存储和数据共享

5.1 本章介绍

  • Container Layer:

  • Data Volume:

  • Docker 持久化数据的方案:

    1. **基于本地文件系统的Volume.**可以在执行Docker create 或 Docker run 时,通过 -v参数将主机的目录作为容器的数据卷。这部分功能便是基于本地文件系统的volume管理。
    2. 基于plugin的Volume,支持第三方的存储方案,比如NAS,aws
  • Volume的类型:

    • 收管理的data Volume,由docker后台自动创建
    • 绑定挂载的Volume,具体挂载位置可以由用户指定。

5.3 数据持久化之Data volume

  • Data Volume 数据卷:

    • 是可以存放在一个或多个容器内特定的目录,提供独立于容器之外的持久化存储;是经过特殊设计的目录,可以绕过联合文件系统(UFS),为一个或多个容器提供访问;
    • 不使用volume的时候,对容器的改动是不会被保存的,使用volume可以实现持久化存储;
    • 运行一个数据库的操作的容器,它里面的数据应该是被持久化存储的,volume就可以实现这个,并且volume可以提供容器与容器之间共享的数据。
  • Docker的理念之一:

    • 将其应用与其运行的环境打包,因此,通常Docker容器的生存周期,都是与在容器中运行的程序相一致的,而我们对数据的要求通常是持久化的;另一方面,docker容器之间也需要有一个共享数据的渠道,而这些需求就催生出了docker数据卷的产生;
  • 数据卷的设计的目的:在于数据的永久化,它完全独立于容器的生命周期,因此,Docker不会在容器删除时删除其挂载的数据卷,也不会存在类似垃圾收集机制,对容器引用的数据卷进行处理了;

  • 数据卷特点:

    1. Docker数据卷是独立于Docker的存在,它存在于Docker host(宿主机)中,因此,它与容器的生存周期是分离的;
    2. Docker数据卷本质上是存在于Docker宿主机的本地文件系统中;
    3. Docker数据卷可以是目录也可以是文件;
    4. Docker容器可以利用数据卷的技术与宿主机进行数据共享;
    5. 同一个目录或者文件,可以支持多个容器进行访问,这样其实实现了容器间的数据的共享和交换;
    6. 数据卷是在容器启动时进行初始化的,那么如果容器使用的镜像包含了的数据也会在容器启动时拷贝到容器的数据卷中;
    7. 数据卷可以在容器之间共享和重用;
    8. 对数据卷的修改会立马生效;容器可以对数据卷里的内容直接进行修改;容器对数据卷进行的修改是及时进行的,所有的修改都会直接体现在数据卷中;
    9. 对数据卷的更新不会影响镜像;因为文件不会写到镜像中去,数据卷是独立于联合文件系统的,而镜像本身基于联合文件系统,so镜像与数据卷之间不会有相互影响的情况;
    10. 数据卷会一直存在,即使挂载数据卷的容器已经被删除;因为数据卷本质上是宿主机上的一个目录,同时为了提供数据的永久化,它的生存周期与容器是完全隔离的;

使用数据卷的命令可百度,此处不赘述。

5.4 数据持久化之Bind Mouting

  • Bind Mounting 的使用只需要将本地目录和要持久化的目录进行绑定即可,命令:

    docker run -v /home/aaa:/root/aaa
    

    Data Volume 需要在Dockerfile内声明需要创建的volume目录,Bind Mounting是在run时声明。

  • 特点:

    • 通过Bind Mounting创建的volume,在我们修改本地的目录时,容器内对应的目录也会跟着更改,因为是同一个volume.

5.5 开发者利器 - Docker+Bind Mouting

  • 我们要做一个容器部署服务,然后通过挂载硬盘,实时对服务内的代码进行修改并实时更新;
  • 步骤如下:
    1. 构建并运行容器:

      • 运行结果如下:
    2. 删除容器:

      docker rm -rf flask
      

      这里删除是为了重新运行容器并同时挂载Mouting,持久化文件。

    3. 构建新的container:

      docker run -d -p 80:5000 -v $(pwd):/skeleton --name flask anyu/flask-skeleton
      

      80宿主机绑定了docker内的5000端口;同时挂载 $(pwd)是指当前目录, 挂载到 skeleton目录下。

    4. 修改挂载的文件夹内的代码:

    5. 刷新后查看网页,发现内容已经变更为最新的代码:

我们可以很方便的根据这个特性去调试,并且它在生产环境里面可以关联着后端、mysql、redis等其他系统及工具,同时也是我们devops的第一步。

六、Docker Compose多容器部署

6.1 根据前面所学部署一个wordpress

  • 官网地址:
  • 安装步骤:
    1. 下载wordpress:

      docker pull wordpress
      
    2. 下载mysql:
      docker pull mysql
      
    3. 运行mysql:
      docker run -d --name mysql -v mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=wordpress mysql
      

      docker run : 启动; --name mysql 命名容器为mysql; mysql-data:/var/lib/mysql 持久化存储至var/lib/mysql目录下; MYSQL_ROOT_PASSWORD 用户名是root,密码也是root; MYSQL_DATABASE 数据库库名为wordpress ; mysql 最后这个表示镜像名称,运行的指定的镜像是mysql;

    4. 运行wordpress:
      docker run -d -e WORDPRESS_DB_HOST=mysql:3306 --link mysql -p 8080:80 wordpress
      

      运行wordpress,并且与mysql进行关联,将wordpress的80端口与主机的8080端口绑定 ;

    5. 进行安装:
    6. 出现此界面说明安装成功:

6.2 Docker Compose到底是什么?

  • 多容器的App太恶心

    • 要从Dockerfile build image或者Dockerhub拉取image
    • 要创建多个container
    • 要管理这些container(启动停止删除)
  • Docker Compose “批处理”

  • Docker Compose

    1. Docker Compose是一个工具
    2. 这个工具可以通过一个yml文件定义多容器的docker应用
    3. 通过一条命令就可以根据yml文件的定义去创建或者管理这多个容器

    所以最关键的就是这个yml文件

  • docker-compose.yml(三大概念)

    • Service
    • Networks
    • Volumes
  • Services:

    1. 一个service代表一个container,这个container可以从dockerhub的image来创建,或者从本地的Dockerfile build 出来的image来创建
    2. Service的启动类类似docker run ,我们可以给其指定network和volume,所以可以给service指定network和Volume的引用;
  • Volumes:指定持久化目录

  • network:定义网络

  • 代码示例:

    通过docker-compose可以批量对container进行管理

6.3 Docker Compose的安装和基本使用

  • 安装docker compose:

    • 如果我们的电脑是mac或者windows,它会随着安装docker一并安装。

      • 查看版本:

        docker-compose -version
        
    • Linux步骤:
      1. 下载docker-compose到指定目录

        sudo curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
        
      2. 给docker-compose可执行权限
        sudo chmod +x /usr/local/bin/docker-compose
        
      3. 查看版本:
        docker-compose --version
        
      4. 前三部操作如图所示:
  • 使用注意点:

    • 输入docker-compose,它会打印支持哪些命令
    • 我们大部分使用docker-compose是配合yml文件一起使用的
    • 输入命令docker-compose up能够启动yml里面的全部文件
    • 输入命令docker-compose ps能够打印启动的全部container
    • 输入命令docker-compose stop 所有一起停止
    • 输入命令docker-compose start启动
    • 输入命令docker-compose down删除里面所有的container。(但是它不会删除本地的镜像)
    • 输入命令docker-compose up -d后台运行,如果需要实时查看日志等,可以不加 -d
    • 输入命令docker-compose images查看docker-compose使用的所有镜像
    • 输入命令docker-compose exec mysql base能够进入mysql的容器里面(这里的mysql可以替换成其他你自己的container名称)
  • redis 的docker-compose.yml代码示例:

docker-compose.yml在启动时,会先构建网络,然后创建镜像,最后再安装顺序先后执行里面的脚本代码创建container;

6.4 水平扩展和负载均衡

  • 我们将用一个示例来展示水平扩展和负载均衡,抛转引玉:

    所以如果我们要水平扩展一个container,我们必须要先安装一个负载均衡器,再使用此命令,同时,应该切断container与宿主机的直接绑定关系,避免端口被占用。用户先访问宿主机,然后再将流量分配到各个水平扩展的container上,所以负载均衡器与container进行绑定。

  • 步骤:
    1. 删除掉要水平扩展的docker-compose.yml文件中的与宿主机的端口映射的关系:
    2. 删除后的文件内容如图:
    3. 水平扩展要扩展的web应用(这里示例是web应用,可以替换为你的镜像)

      web=3 就会新建3个 -d是后台运行 --scale就是水平扩展的意思。 web=10就会从3个变成10个,当不需要那么多的时候也可以减少,将web=10改成更小的数字(实际业务场景:用户访问峰值变高,可以增加container,访问变少可以减少container)

    4. 在web应用中监听80端口:
    5. 在docker-compose.yml中增加一个haproxy负载均衡,并将自己的80端口映射到本地8080端口
    6. 增加了负载均衡后,水平扩展的web应用就能够被负载均衡了,宿主机里面可以随机访问者三个web:

    docker-compose的scale是单机上的,很多时候场景并不适合,我们大部分情况需要多机器情况下进行,后面我们会将容器编排。

七、容器编排Docker Swarm

7.1 容器编排Swarm介绍

  • Swarm简介:

    • Swarm背景:

      • 现实中我们的应用可能会有很多,应用本身也可能很复杂,单个Docker Engine所能提供的资源未必能够满足要求。而且应用本身也会有可靠性的要求,希望避免单点故障,这样的话势必需要分布在多个Docker Engine。在这样一个大背景下,Docker社区就产生了Swarm项目。
    • Swarm是什么?
      • Swarm这个项目名称特别贴切。在Wiki的解释中,Swarm behavior是指动物的群集行为。比如我们常见的蜂群,鱼群,秋天往南飞的雁群都可以称作Swarm behavior。

      Swarm项目正是这样,通过把多个Docker Engine聚集在一起,形成一个大的docker-engine,对外提供容器的集群服务。同时这个集群对外提供Swarm API,用户可以像使用Docker Engine一样使用Docker集群。

    • Swarm特点:
      1. 对外以Docker API接口呈现,这样带来的好处是,如果现有系统使用Docker Engine,可以平滑将Docker Engine切换到Swarm上,无需改动现有系统。
      2. Swarm对用户来说,之前使用Docker的经验可以继承过来,非常容易上手,学习成本和二次开发成本都比较低。同时Swarm本身专注于Docker集群管理,非常轻量,占用资源也非常少。“Batteries included but swappable”,简单说,就是插件化机制,Swarm中的各个模块都抽象了API,可以根据自己一些特点进行定制实现。
      3. Swarm自身对Docker命令参数支持的比较完善,Swarm目前与Docker是同步发布的。Docker的新功能,都会第一时间在Swarm中体现。
  • 为什么要使用容器编排:
    1. 在学习本章之前,所有的docker都在一个机器上:
    2. 到处都使用容器 = 麻烦来了:
      1. 怎么去管理这么多容器?
      2. 怎么能方便的横向扩展?
      3. 如果容器down了,怎么能自动恢复?
      4. 如何去更新容器而不影响业务?
      5. 如何去监控追踪这些容器?
      6. 怎么去调度容器的创建?
      7. 保护隐私数据?

      所以我们需要一个容器编排系统,去多机器的批量管理容器。

    3. Swarm Mode:

      只要我们安装了docker就安装了Swarm(已内置,不需要安装其他额外的东西),只不过我们平时是运行在单机的模式下。它是我们初学者第一个接触的容器编排工具。

    4. Docker Swarm Mode Architecture
    5. Service和Replicas:
    6. 容器创建和调度:

7.2 创建一个三节点的Swarm集群

  • 有三种方式:

    1. Vagrant+Virtualbox (十几分钟)
    2. Docker Machine + Virtualbox(几分钟)
    3. Paly with docker https://labs.play-with-docker.com/ (1,2分钟左右,但是它只能保存4个小时)
  • 使用Vagrantfile

    1. 创建三台主机:
    2. 等待三台主机启动成功,出现如下内容说明启动成功:
    3. 使用vagrant命令进入到名称为swarm-manager的主机里:
      vagrant ssh swarm-manager
      
    4. 查看docker swarm支持哪些命令,输入命令如下:docker swarm --help ,然后展示的内容如图所示:
    5. 我们要进行初始化,输入命令docker swarm init --help查看初始化有哪些参数:
    6. 运行manager节点,输入以下命令:
      docker swarm init --advertise-addr=192.168.205.10
      

      第一个初始化的节点是我们的swarm manager节点,所以我们要先在要manager的节点上进行初始化。

    7. 查看步骤6命令是否运行成功,并复制好: add a worker的命令:
    8. 退出当前manager节点的服务器:
      exit
      
    9. 连接作为work1节点的服务器:
      vagrant ssh swarm-worker1
      
    10. 运行刚才复制的add a worker的节点命令:
    11. 重新进入manager节点:
      vagrant ssh swarm-manager
      
    12. 使用swarm命令查看节点状态(验证刚才安装的worker节点是否绑定到了这个manager中没)
      • 命令:

        docker node ls
        
      • 图示:
    13. 连接第二个work节点所在的服务器:
      vagrant ssh swarm-worker2
      
    14. 启动docker(如果docker已启动则忽略此步骤)
      sudo service docker start
      
    15. 输入之前复制的add a worker 命令,将此服务器内的此docker加入manager,作为一个worker:

    走到这里,三个节点都创建成功了。这里是一个manager,两个worker。

  • 使用docker-machine与Paly with docker 的方式搭建与Vagrantfile类似,实际上就是三台主机,然后分别运行一个manager、两个worker命令即可。

7.3 Serice的创建维护和水平扩展

  • docker service 的常用命令:

    1. 使用帮助命令:

      docker service
      

      使用此命令可以看到它下面的所有可使用命令,如图所示:

    2. 使用命令创建一个示例docker应用(创建service的格式是:docker service create [OPTIONS] IMAGE [COMMAND] [ARG...] [flags]):
      docker service create --name demo busybox sh -c "while true;do sleep 3600;done"
      

      demo是container的名称,busybox是镜像, sh -c 是里面要执行的脚本内容;

    3. 使用docker service的ls 命令查看已运行的docker应用:
      docker service ls
      

      使用此命令来检查刚才创建的demo 的container是否运行成功;如图所示:

    4. 查看指定container的详细信息:
      docker service ps demo
      

      使用此命令可以打印出demo container的运行状态、名称、ID、使用镜像名、端口、节点(即哪台服务器上),这里的demo可以替换成你自己的container名称;

    5. 通过步骤4看出此container运行在manager服务器上,说明是我们现在这台服务器,我们运行docker ps查看是否存在此container。如图所示:
    6. 使用docker service 进行水平扩展,将此container扩展为5个
      docker service scale demo=5
      

      这个scale 跟上一章节的水平扩展一样,支持扩展和缩容,如果=5个就建5个container,如果=1个就改为运行1个container。同时如果有任意一个container宕机了,docker service 还能监测到并且重启启动一个以保持预计的数量;

    7. 使用docker service命名来查看demo的container详细信息:
      • 代码:

        docker service ps demo
        
      • 图示:

      启动五个,它分别在manager/worker1/worker三台服务器(虚拟机)上运行了demo 的container,以使总数达到5个。

    8. 在指定的服务器上如果宕机(或者删除等)导致一个container运行失败,manager服务器上的service会自动监测到,并且重新运行一个container。如图所示:
    9. 删除demo
      docker service rm demo
      

      在manager服务器节点上调用删除方法能够一次性删除全部的已注册container。(避免了登录每台服务器然后一个一个的删除)

docker service 的命令是在manager节点所在的服务器上运行的。

7.4 在swarm集群里通过serice部署wordpress

  • 操作步骤:

    1. 创建网络:

      docker network create -d overlay demo
      
    2. 查看网络:
      docker network ls
      

      出现使用镜像overlay 的名称为demo 的container 则表示步骤1创建成功

    3. 创建mysql container:
      docker service create --name mysql --env MYSQL_ROOT_PASSWORD=root --env MYSQL_DATABASE=wordpress --mount type=volume,source=mysql-data,destination=/var/lib/mysql mysql
      
    4. 查看是否运行成功以及运行在哪个节点上:
    5. 创建wordpress container:
      docker service create --name wordpress -p 80:80 --env WORDPRESS_DB_PASSWORD=root --env WORDPRESS_DB_HOST=mysql --network demo wordpress
      
    6. 查看是否运行成功以及运行在哪个节点上:
      docker service ps wordpress
      
    7. 在本地进行访问wordpress,查看是否能访问成功:

docker service 的命令是在manager节点所在的服务器上运行的。

7.5 集群服务间通信之Routing Mesh

  • 概念:

    • 无论访问哪个节点,即使该节点没有运行service的副本,最终都能访问到service.
    • 在swarm中使用ingress network,需要防火墙允许以下端口通过:7946 、 4789
    • 当我们访问任何节点的8080端口时,swarm内部的load balancer会将请求转发给web_server其中一个副本。
  • DNS 服务发现
  • Routing Mesh 的两种体现:
    1. Internal: Container 和Container之间的访问通过overlay网络(通过VIP虚拟IP)
    2. Ingress:如果服务有绑定接口,则此服务可以通过任意swarm节点的相应接口访问。
  • Internal Load Balancing
  • DNS+VIP_iptables+LVS

7.6 Routing Mesh 之Ingress 负载均衡

  • Ingress Network

    • 外部访问的负载均衡
    • 服务端口被暴露到各个swarm节点
    • 内部通过IPVS进行负载均衡
    • 图示:
  • 查看本地转发规则命令:
    sudo iptables -nl -t nat
    
  • Ingress Network 的数据包走向详情

7.7 Docker Stack部署

  • 简介:

    • Docker有个编排工具docker-compose,可以将组成某个应该的多个docker容器编排在一起,同时进行管理。同样在Swarm集群中,可以使用docker stack将一组关联的服务进行编排管理。Docker stack也是一个yaml文件,和一份docker-compose.yml文件差不多,指令也基本一致。但是与compose相比其不支持build、links和network_mode。Docker stack有一个新的指令deploy.
    • stack不支持的指令有:
      • build
      • cgroup_parent
      • container_name
      • devices
      • tmpfs
      • external_links
      • links
      • network_mode
      • restart
      • security_opt
      • stop_signal
      • sysctls
      • userns_mode
  • Deploy:
    • 简介:Deploy是用来指定swarm服务部署和运行时的相关配置,并且只有使用docker stack deploy部署swarm集群才会生效。如果使用docker-compose up 或者docker-compose run时,该选项会被忽略。要使用deploy选项,compose-file中version版本要在3或者3+.
  • 查看官网,了解deploy及相关的命令:
  • deploy及其子命令:
    1. endpoint_mode:(指定swarm服务发现的模式)

      • vip模式:

        1. Docker为swarm集群服务分配一个虚拟IP(VIP),作为客户端到达集群服务的“前端”。
        2. Docker在客户端和可用工作节点之间对服务的请求进行路由,而客户端不用知道有多少节点参与服务或者这些节点的IP/端口。(这是默认模式)
      • dnsrr:
        1. DNS轮询(DNSRR)服务发现不使用单个虚拟IP。
        2. Docker为服务设置DNS条目,使得服务名称的DNS查询返回一个IP地址列表,并且客户端直接连接到其中的一个。
        3. 如果您想使用自己的负载均衡器,或者混合Windows和Linux应用程序,则DNS轮询功能费长有用。
      • 代码示例:
        version: "3.3"services:wordpress:image: wordpressports:- 8080:80networks:- overlaydeploy:mode: replicatedreplicas: 2endpoint_mode: vipmysql:image: mysqlvolumes:- db-data:/var/lib/mysql/datanetworks:- overlaydeploy:mode: replicatedreplicas: 2endpoint_mode: dnsrrvolumes:db-data:networks:overlay:
        
    2. LABELS(指定服务的标签。)

      1. 这些标签仅在服务上设置,而不在服务的任何容器上设置,代码示例:

        version: "3"
        services:web:image: webdeploy:labels:com.example.description: "This label will appear on the web service"
        
      2. 要改为在容器上设置标签,请在deploy之外使用标签键:
        version: "3"
        services:web:image: weblabels:com.example.description: "This label will appear on all containers for the web service"
        

        主要是设置一些帮助和描述信息

    3. MODE(扩展模式)

      • 一种是global,一种是replicated.默认的配置是replicated,我们一般不经常去设置它。使用global命令则不能对容器应用进行横向扩展。
      • global的意思是全局,即每个集群节点只有一个容器。
      • replicated的意思是副本,指定容器的数量。
      • 代码示例:
        version: '3'
        services:worker:image: dockersamples/examplevotingapp_workerdeploy:mode: global
        
    4. PLACEMENT(指定约束和偏好设置)

      • 代码示例:

        version: '3'
        services:db:image: postgresdeploy:placement:constraints:- node.role == manager- engine.labels.operatingsystem == ubuntu 14.04preferences:- spread: node.labels.zone
        

        比如node.role == manager,则此容器创建只会在manager节点上进行创建。

    5. REPLICAS(如果服务时副本模式(默认模式),可以指定该服务运行的容器数量)

      • 代码示例:

        version: '3'
        services:worker:image: dockersamples/examplevotingapp_workernetworks:- frontend- backenddeploy:mode: replicatedreplicas: 6
        

        这里的replicas设置为了6个,则它在一开始进行部署时,就会默认创建6个container。它就是sacle命令的默认配置;

    6. RESOURCES(资源限制配置)

      • 代码示例:

        version: '3'
        services:redis:image: redis:alpinedeploy:limits:cpus: '0.50'memory: 50Mreservations:cpus: '0.25'memory: 20M
        

        代码中limits里面设置了(上限)cpu和内存的最大限制数量、而reservations里面则对此容器保留(拥有)了多少cpu性能和内存大小。

    7. RESTART_POLICY(配置在容器退出时是否并如何重启容器)。取代restart指令

      • condition: none、on-failure和any (默认any)
      • delay: 在重启尝试之间等待多久 (默认0)
      • max_attempts: 尝试重启的次数(默认一直重启,直到成功)
      • window: 在确定一个重启是否成功前需要等待的窗口时间:
      • 代码示例:
        version: "3"
        services:redis:image: redis:alpinedeploy:restart_policy:condition: on-failuredelay: 5smax_attempts: 3window: 120s
        

      condition:要不要重启,重启的条件是什么。delay延迟。max_attempts最大重启次数。

    8. UPDATE_CONFIG(配置服务如何升级)

      • parallelism: 同一时间升级的容器数量
      • delay:容器升级间隔时间
      • failure_action:升级失败后的动作(continue、rollback和pause。默认pause).
      • monitor: 更新完成后确实成功的时间(ns | us| ms| s| m| h).(默认0s)
      • max_failure_ratio:更新期间允许的失败率
      • order:更新期间的操作顺序。停止优先(旧任务在开始新任务之前停止)或者先启动(首先启动新任务,并且正在运行的任务短暂重叠)(默认停止优先)注意:只支持v3.4及更高版本。
      • 代码示例:
        version: '3.4'
        services:vote:image: dockersamples/examplevotingapp_vote:beforedepends_on:- redisdeploy:replicas: 2update_config:parallelism: 2delay: 10sorder: stop-first
        

      配置更新时的一些原则

    9. depends_on(表示服务之间的依赖关系)

      version: '3'
      services:web:build: .depends_on:- db- redisredis:image: redisdb:image: postgres
      
    10. dns(自定义DNS服务器,可以是单个值或列表)

      dns: 8.8.8.8
      dns:- 8.8.8.8- 9.9.9.9
      
    11. dns_search

      dns_search: example.com
      dns_search:- dc1.example.com- dc2.example.com
      
    12. environment(添加环境变量。您可以使用数组或字典。任何布尔值;真/假,是/否,需要用引号括起来以确保它们不被YML解析器转换为True或False)

      environment:RACK_ENV: developmentSHOW: 'true'SESSION_SECRET:environment:- RACK_ENV=development- SHOW=true- SESSION_SECRET
      
    13. expose(开放容器的端口而不用在主机上暴露端口,它们只能被相关联的服务获取。只能指定内部端口)

      expose:- "3000"- "8000"
      
  • 接下来我们做一个示例,对docker-compose.yml进行一些改造,然后用Docker Stack部署Wordpress:
    1. 先看一下以前的docker-compose.yml文件内容:

    2. 改造网路,将bridge。

      • 图示:

      在Swarm中,容器可能分布在不同的机器上,要将bridge改为overlay。

    3. 为mysql增加Stack相关的设置:

      1. 包含以下设置:

        1. 添加deploy
        2. 设置mode为global模式(不能动态扩容)
        3. 将节点运行在manager服务器上
      2. 代码示例:
    4. 为wordpress增加Stack相关的设置:

      • 代码示例:
    5. 进入到服务器,查看Docker stack相关支持的命令:

      1. 命令如下:

        docker stack
        
      2. 展示的命令列表如图所示:
      3. 在docker-compose.yml内容中,为了避免冲突,将名称从wordpress改为web:
      4. 运行命令时出现错误,我们进行修复:
        1. 错误图示如下:
        2. 处理方式:
          • 针对问题一,增加了placement的前缀:
          • 针对问题二,我们将order属性删除,update_config删除order配置后的内容:
      5. 运行wordpress,并指定compose-file路径:
        • 命令如下:

          docker stack deploy wordpress --compose-file=docker-compose.yml
          
        • 图示如下:

        自动加了一个wordpress的前缀

      6. 查看运行的数量:
        • 命令如下:

          docker stack ls
          
        • 图示如下:
      7. 查看运行的container的详细信息:
        • 命令如下:

          docker stack ps wordpress
          
        • 图示如下:
      8. 本地访问wordpress安装服务器地址,查看是否安装成功:
      9. 使用删除命令,一次性删除manager及其他节点上的创建的全部wordpress(通过yml文件构建的wordpress、mysql、以及网络network都会被删除掉。)
        • 命令如下:

          docker stack rm wordpress
          
        • 图示如下:

    docker-compose.yml之前可以使用build命令,这种方式是不能使用了。

7.8 Docker Secret管理和使用

  • 什么是Secret?

    • 用户名密码
    • SSH Key (私钥不让别人知道)
    • TLS认证
    • 任何不想让别人看到的数据
  • Docker Secret的架构: Docker Searm Mode Architecture

    • 图示:
    • 内容解读:
      1. Manager里面有一个分布式存储,它是基于Raft协议,能够让相互之间的节点数据进行同步(同时是加密存储到硬盘的,天然的加密环境)。
      2. 建议manager 在生产环境中最少要有2个,因为如果一旦一个节点故障宕机了,那么整个swarm都是不可用的,这个代价太大了。
      3. Manager节点与Worker节点之间是TLS加密通信的,worker节点的一些key信息也是存储在manager节点的分布式存储里面的。所以我们也可以存储一些secret在里面。
  • Secret Management

    1. 存在Swarm Manager节点Raft database里
    2. Secret可以assign给一个service,这个service就能看到这个secret
    3. 在container内部Secret看起来像文件,但是实际是在内存中。

7.9 Docker Secret在Stack中的使用

  • 在指定文件使用Secret:

  • 若不存在此文件可在docker-compose.yml中设定创建:

  • 实战测试:

    • 第一种创建方法(通过文件读取)

      1. 创建一个文件(secret的文件):

        vim password
        
      2. 在文件中写入密码,示例如下:
        p@ssw0rd
        
      3. 创建一个secret,指明来源于pssword文件(就是数据读取自上面创建的文件):
        docker secret create my-pw password
        
      4. 删掉原来的文件,因为我们的secret已经加载了密码了,所以要销毁掉之前的文件。
        rm -rf password
        
      5. 使用docker secret ls命令可以查看secret是否创建成功,如图所示:
    • 第二种secret创建方法(直接命令中创建密码):
      1. 创建命令:

        echo "p@ssw0rd" | docker secret create my-pw2 -
        

        p@ssw0rd是我们在线创建的密码。

  • 常用secret命令:

    1. secret帮助:

      docker secret COMMAND
      
    2. 删除指定的secret:
      docker secret rm my-pw2
      

      其中my-pw2是被删除的secret名称

  • 在Docker Service中使用secret:

    1. 创建一个示例service:

      docker service create --name client --secret my-pw busybox sh -c "while true; do sleep 3600; done"
      

      这里面使用了名称为my-pw的secret

    2. 查看容器是否启动成功:
      docker service ps client
      
    3. 查看容器运行信息:
      docker ps
      
    4. 进入到容器里面:
      docker exec -it ccee sh
      

      ccee是具体的容器名称。

    5. 进入到secret保存的目录:
      cd /run/secrets/
      
    6. 查看刚才传入的secret:
      cat my-pw
      

    总的来说就是docker service执行时选择指定的secret,然后在容器内部的run/secrets目录中可以找到这个文件。而且传入的时候,也可以传入多个;

  • 实战案例–mysql中使用secret:

    1. 运行mysql容器创建命令,并传入secret:

      docker service create --name db --secret my-pw -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/my-pw mysql
      
    2. 查看容器是否创建成功:
      docker service ls
      
    3. 查看指定容器在哪个服务器上创建了:
      docker service db
      

      这个db是指上面创建的容器,如果你的容器不叫这个,相应替换即可。

    4. 进入到运行这台容器的服务器里面:
      vagrant ssh swarm-worker1
      

      如果不是用vagrant创建的服务器,直接用你的方式进入即可。这里的swarm-worker1代指服务器名称

    5. 在此台服务器中查看是否存在此容器在运行:
      docker ps
      
    6. 进入此容器中:
      docker exec -it $容器id sh
      
    7. 查看此容器的指定目录是否存在此secrets:
      ls /run/secrets
      
    8. 登录mysql:
      mysql -u root -p
      
    9. 输入密码,传入 ls /run/secrets中指定的secret内的密码内容,然后发现能够成功登录mysql,说明secret配置成功!

    这个案例就是将secret作为mysql的密码,在容器一开始运行的时候进行了设定。只有拥有linux中有此容器访问权限的人才有可能知道密码是什么,也就才能登录这个mysql了。

八、Deops初体验 – Docker Cloud 和Docker企业版

8.1 Docker 的收费模式

  1. 收费课程
  2. 认证证书
  3. Docker认证容器(部分收费)
  4. Docker Cloud(网页版命令行)

8.2 Docker Cloud 简介

  • 什么是Docker Cloud?

    • Docker Cloud 是caas(Container as a Service)容器即服务,阿里云和腾讯云属于paas平台即服务,caas是在paas之上的,我们要提供docker的service,必须要有底层infrastructure的支持,paas他们虚拟的计算资源,在这些虚拟资源之上在进行搭建docker的微服务;
    • Docker Cloud,Docker在2015年11月收购了tutum.co在今年2月份推出了Docker Cloud,它基本上提供了Docker自身原生的一个编排的API;
    • 提供容器的管理、编排、部署的托管服务
  • 主要模块:
    • 关联云服务商,如:AWS,Azure
    • 添加节点作为Docker Host
    • 创建服务,Service
    • 创建Stack
    • Image管理
  • 两种模式:
    1. Standard模式:一个Node就是一个Docker Host
    2. Swarm模式(beta),多个Node组成的Swarm Cluster
  • devops流程图

    我们开发人员先在本地进行编写代码,然后可以用容器模拟生产环境做本地测试,测试通过后将代码提交至主分支,然后持续集成CI,自动构建Docker镜像,再持续部署CD,在云服务器上自动创建或更新服务。

8.3 Docker Cloud之自动build Docker image

步骤如下:
1. 绑定代码:

8.4 Docker Cloud之持续集成和持续部署

8.5 Docker企业版的在线免费体验

8.6 Docker企业版本地安装之UCP

8.7 Docker企业版本地安装之DTR

8.8 Docker企业版UCP的基本使用演示

8.9 体验阿里云的容器服务

8.10 在阿里云上安装Docker企业版

8.11 Docker企业版DTR的基本使用演示

九、容器编排Kubernetes

9.1 Kubernetes简介

  • Docker Swarm与Kubernetes一起作为一种容器编排的解决方案:

    • Docker Swarm Mode Architecture(Docker Swarm的架构):

      • 图示:
      • 概述:
        • Docker Swarm分为Worker节点和Manager节点。
        • 而Manager节点具备管理的功能,主要去维持Cluster的状态,并且提供对外的接口。
        • 我们可以通过Manager来部署我们的Application(应用),Service,Stack。
    • Kubernetes Architecture(k8s的架构)
      • 图示:
      • 概述:
        • 它与Docker Swarm类似(这种分布式集群从大的方面来讲都是一样的,都有manager和worker).
        • Docker Swarm中的Manager节点在k8s中我们称为 Master节点 ,worker节点这里称为node节点。
        • Master会提供一些接口,这些接口可以对整个K8s集群进行一些操作,比如说可以看一下Cluster集群的节点状态,通过K8s命令将我们的App部署到K8s集群中去等等
  • Kubernetes Master(k8s集群的大脑)的模块:

    • 图示:
    • 讲解:
      1. Api Server:交互模块。暴露给外界访问,我们可以通过CLI工具或者UI界面调用API Server跟整个集群交互。
      2. Scheduler:调度模块。比如说用户通过Api Server下达了创建2个容器的命令,到底在哪个Node节点上进行创建,这就是Scheduler的职责所在了。它内部有一些调度算法。
      3. Controller,控制模块。比如说我们容器要做一个负载均衡,要做一个容器扩展,将一个容器扩展为5个,并且维持它一直是5个的状态。
      4. etcd: 存储模块。主要存储整个K8s的状态和配置;
  • Kubernetes Node:

    • 图示:
    • 讲解:
      • Pod:

        • 它是一个最小单位,具有相同NameSpace的一些Container组合。这个NameSpace包含了所有NameSpace,包含了UserSpace,NetworkSpace(主要是这个)。
        • 具有相同NetworkSpace的组合,这个容器可能有一个或者多个。如果是多个的话,它们是共享一个NetworkSpace
      • Docker: 创建容器的技术
      • Kubelet:
        • 它是在每个Node节点上运行的主要“节点代理”。它可以使用以下之一向apiService注册:主机名(hostname);覆盖主机的参数;某云驱动的特定逻辑;
        • 它是基于PodSpec来工作的。每个PodSpec是一个描述Pod的YAML或JSON对象。kubelet接受通过各种机制(主要是通过apiserver)提供的一组PodSpec,并确保这些PodSpec中描述的容器处于运行状态且运行状况良好。Kubelet不管理不是由kubernetes创建的容器。
      • kube-proxy:它跟网络有关。k8s中有service概念,假如有一些service想暴露端口让外界访问,那我们需要kube-proxy帮我们做一些端口代理和转发。当然在k8s中,service也可以做负载均衡,但是它的服务发现和负载均衡也是通过kube-proxy来实现的。
      • Fluentd:主要做日志的采集、存储、查询的。
      • Optional Add-ones: 提供的插件。
      • Image Registry,从Image上来拉取镜像
  • k8s集群:

9.2 Minikube快速搭建K8s单节点环境

9.3 K8s最小调度单位Pod

  • 讲解:

    1. Pod:

      1. 介绍:

        1. 它是容器调度的一个最小单位,最小部署单元
        2. 一组容器的集合
        3. 一个Pod中的容器共享网络命名空间
        4. Pod是短暂的
      2. Pod存在的意义:
        1. Pod为亲密性应用而存在
        2. 亲密性应用场景:
          1. 两个应用之间发生文件交互
          2. 两个应用需要通过127.0.0.1或者socket通信
          3. 两个应用需要发生频繁的调用。
      3. Pod实现机制与设计模式(Pod本身是一个逻辑概念,没有具体的存在,那么是如何实现的呢?):
        1. 共享网络:K8s的解法是这样的,会在每个Pod里先启动一个infra container小容器,然后让其他的容器连接进来这个网络命令空间,然后其他容器看到的网络视图就完全一样了,即网络设备、IP地址、Mac地址等,这就是解决网络共享问题。在Pod的IP地址就是infra container的IP地址。
        2. 共享存储: 比如有两个容器,一个是nginx,另一个是普通的容器,普通的容器要想访问nginx里的文件,就需要nginx将共享目录通过volume挂载出来,然后让普通容器挂载这个volume,最后大家看到这个共享目录的内容一样。
      4. Pod中容器分为以下几个类型:
        1. Infrastructure Container: 基础容器,维护整个Pod网络空间,对用户不可见。
        2. InitContainers:初始化容器,先于业务容器开始执行,一般用于业务容器的初始化工作;
        3. Containers: 业务容器,具体跑应用的镜像
      5. 镜像拉取策略:
        • 代码示例:

          apiVersion: v1
          kind: Pod
          metadata:name: my-pod
          spec:containers:- name: javaimage: a13552821243/java-demoimagePullPolicy: IfNotPresent
          
        • imagePullPolicy字段有三个赋值:
          • IfNotPresent: 镜像在宿主机不存在时才拉取
          • Always:默认值,每次创建Pod都会重新拉取一次镜像
          • Never: Pod永远不会主动拉取这个镜像

        如果拉取公开的镜像,直接按照上述示例即可,但要拉取私有的镜像,是必须认证镜像仓库才可以,即docker login,而在K8s集群中会有多个Node,显然这种方式很不方便的。为了解决这个问题,k8s实现了自动拉取镜像的功能。以secret方式保存到K8s中,然后传给kubelet.

      6. 资源限制:
        1. 申请配额:调度时使用,参考是否有节点满足该配置。

          spec.containers[].resources.limits.cpu
          spec.containers[].resources.limits.memory
          
        2. 限制配额:容器能使用的最大配置。
          spec.containers[].resources.requests.cpu
          spec.containers[].resources.requests.memory
          
        3. 代码示例:
          apiVersion: v1
          kind: Pod
          metadata:name: web
          spec:containers:- name: javaimage: a13552821243/java-demoresources:requests:memory: "64Mi"cpu: "250m"limits:memory: "128Mi"cpu: "500m"
          
      7. 重启策略:
        • 代码示例:

          apiVersion: v1
          kind: Pod
          metadata:name: my-pod
          spec:containers:- name: javaimage: a13552821243java-demorestartPolicy: Always
          
        • restartPolicy字段有三个可选值:
          • Always:当容器终止退出后,总是重启容器,默认策略
          • OnFailure:当容器异常退出(退出状态码非0)时,才重启容器。适用于job
          • Never:当容器终止退出,从不重启容器。适于job
      8. 健康检查:
        • 默认情况下,kubelet根据容器状态作为健康依据,但不能判断容器中应用程序的状态,例如程序假死。这就会导致无法提供服务,丢失流量。因此引入健康检查机制确保容器健康存活。
        • 健康检查有两种类型:
          • livenessProbe:

            • 如果检查失败,将杀死容器,根据Pod的restartPolicy来操作。
          • readinessProbe:
            • 如果检查失败,Kubernetes会把Pod从service endpoints中剔除。
        • 这两种类型支持三种检查方法(Probe支持以下三种检查方法):
          • httpGet: 发送HTTP请求,返回200~400范围状态码为成功。
          • exec:执行Shell命令返回状态码是0为成功。
          • tcpSocket: 发起TCP Socket建立成功。
        • 代码示例:
          apiVersion: v1
          kind: Pod
          metadata:labels:test: livenessname: liveness-exec
          spec:containers:- name: livenessimage: busyboxargs:- /bin/sh- -c- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 60livenessProbe:exec:command:- cat- /tmp/healthyinitialDelaySeconds: 5periodSeconds: 5
          

          上述示例,启动容器第一件事创建文件,停止30s,删除该文件,再停止60s,确保容器还在运行中。验证现象:容器启动正常,30s后异常,会restartPolicy策略自动重建,容器继续正常,反复现象。

      • 调度策略:

        • 创建一个Pod的工作流程:create pod -> apiserver -> write etcd -> scheduler -> bind pod to node -> write etcd -> kubelet( apiserver get pod) -> dcoekr api,create container -> apiserver -> update pod status to etcd -> kubectl get pods
        • 如图所示:
        • Pod根据调度器默认算法将Pod分配到合适的节点上,一般是比较空闲的节点。但有些情况我们希望将Pod分配到指定节点,该怎么做呢?这里给你介绍调度策略:nodeName、nodeSelector和污点

9.4 ReplicaSet和ReplicationController

9.5 Deployment

9.6 使用Tectonic在本地搭建多节点k8s集群

9.7 k8s基础网络Cluster Network

9.8 Serice简介和演示

9.9 NodePort 类型Serice以及Label的简单使用

9.10 准备工作—使用kops在亚马逊上搭建k8s集群

9.11 使用kops在亚马逊AWS上搭建k8s集群

9.12 LoadBlancer类型serice以及AWS的DNS服务配置

9.13 在亚马逊k8s集群上部署wordpress

十、Kubernetes简介和安装

10.1 Kubernetes简介

10.2 k8s安装的方法简介

10.3 在windows系统上安装使用minikube

10.4 在Mac系统上安装使用minikube

10.5 使用kubeadm搭建多节点k8s集群

10.6 Google云平台的k8s服务

十一、Kubernetes中的基本概念和操作

11.1 kubectl的基本使用

11.2 k8s的节点和标签

11.3 k8s调度的最小单位pod

11.4 Namespace命名空间

11.5 创建我们自己的context

11.6 Controller 和 Deployment

11.7 deployment的演示

11.8 Replicaset在Deployment更新中的作用

十二、容器的运维和监控

12.1 容器的基本监控

12.2 k8s集群运行资源监控—Heapster+Grafana+InfluxDB

12.3 根据资源占用自动横向伸缩

12.4 k8s集群Log的采集和展示

12.5 k8s集群监控方案Prometheus

十三、Docker+Deops实战 – 过程和工具

13.1 本章简介

13.2 搭建GitLab服务器

13.3 搭建GitLab CI服务器和Pipeline演示

13.4 简单java项目的CI演示

13.5 CI实现版本自动发布

十四、博文总结

一周左右完善~

Devops系统化,从零开始学习容器技术(更新中)相关推荐

  1. Linux 学习 -- 容器技术

    Linux 学习 – 容器技术 容器基础概述 容器部署 一.容器基础概述 容器(Container) : 定义:指的是针对应用所需的运行环境资源(依赖库/目录/网络/用户--等)进行整体封装的技术. ...

  2. [0 to 0.5]从零开始学习Android动画知识(中)

    [0 to 0.5]从零开始学习Android动画知识(中) 属性动画(Property Animation) 属性动画(Property Animation)是在 Android 3.0(API 1 ...

  3. linux常见命令---深度学习炼丹炉必备---更新中

    目录 linux常见命令---深度学习炼丹炉必备---更新中 1.修改环境变量 2.查看当前conda环境 3.如果执行conda activate ***出现问题时需要初始化shell 4.查看当前 ...

  4. typescript-----javascript的超集,typescript学习笔记持续更新中......

    Typescript,冲! Typescript 不是一门全新的语言,Typescript是 JavaScript 的超集,它对 JavaScript进行了一些规范和补充.使代码更加严谨. 一个特别好 ...

  5. 人生最好的php,mysql,linux,redis,docker等相关技术经典面试题,新手收藏学习,持续更新中。。。

    php面试题 1.写出你能想到的所有HTTP返回状态值,并说明用途(比如:返回404表示找不到页面) # 200:服务器请求成功 # 301:永久重定向,旧网页已被新网页永久替代 # 302:表示临时 ...

  6. 技术胖前端学习路线学习笔记【更新中】

    文章目录 技术胖前端学习路线学习笔记 1. 网络知识 2. 超文本标记语言(HTML) 3.层叠样式表(CSS) 4.浏览器脚本语言(JavaScript) 5.版本控制管理系统Version Con ...

  7. Docker快速入门学习笔记-持续更新中

    Docker安装 #1.卸载旧的版本 yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker ...

  8. mybatis delete返回值_从零开始学习在IntelliJ IDEA 中使用mybatis

    纯新手,打算学习下mybatis的用法,在官网和教程上看了资料,整理下笔记. 既然是从零开始,就是不依赖任何框架和模板,从空白项目开始.在IDEA上先新建一个空的java项目. 1. 添加项目依赖 需 ...

  9. JS逆向学习笔记 - 持续更新中

    JS逆向学习笔记 寻找深圳爬虫工作,微信:cjh-18888 文章目录 JS逆向学习笔记 一. JS Hook 1. JS HOOK 原理和作用 原理:替换原来的方法. (好像写了句废话) 作用: 可 ...

最新文章

  1. macsv服务器状态,和利时macs问题(启动服务器无法读出控制器的点名)
  2. 有窗体和无窗体覆盖的问题
  3. FFMPEG设置 cbr讨论
  4. 深入分析Java中的关键字static
  5. 8天学通MongoDB——第四天 索引操作
  6. 正则表达式之子表达式 ‘()’ 中表达式 '[]' 大表达式 '{}'
  7. echo字符集 shell_Shell echo命令:输出字符串
  8. {面试题4: 替换空格}
  9. 「小程序JAVA实战」小程序页面的上拉下拉刷新(50)
  10. c语言在线电子词典的实验报告,《第十六周实验报告任务3——电子词典》
  11. C语言!鸡兔同笼的程序
  12. 如何快速成为数据分析师
  13. 雷电3菊链功能_雷电3接口是什么
  14. matlab 柱状图怎么叠加,如何让柱形图重叠起来
  15. i-Refill | 张益唐:虽未实现大海捞针,但摸透了整个海底的情况
  16. 【新知实验室 陈林】
  17. 如何求地球上两点之间的最短距离_初中数学求线段之和最小的问题,知识点题型汇总...
  18. 《薛兆丰的经济学课》课程总结3--生命有限
  19. 集成推送(极光+小米+华为)总结(java服务端)
  20. Mac 常用软件注册码

热门文章

  1. 示波器探头有X1和X10档,当测量一个信号时应该如何选择?
  2. 递归函数——头递归和尾递归
  3. 【环境配置】临时更改pip源至清华、阿里、中科大镜像
  4. IE8打不开网页提示sysfader错误的解决办法
  5. java使用pd4ml实现html文件转pdf
  6. 关于在寒假用两周从零手写包含模拟着色器的软渲染器这件事
  7. 摇一摇手机控制手机录音功能
  8. uniapp实现h5录音功能
  9. 鸿蒙版瑞幸咖啡开发日记(三)购物车结算栏开发
  10. 美国人这样教育小学生(转贴)