第一章、容器技术和Docker简介
一、long time ago
二、虚拟化技术
- 结构
- 特点:
- 一个物理机可以部署多个app
- 每个app独立运行在一个VM里
- 优点:
- 资源池:一个物理机的资源分配到了不同的虚拟机里
- 很容易拓展:加物理机器or加虚拟机
- 很容易云化:亚马逊AWS,阿里云
- 局限性:
- 每个虚拟机都是一个完整的操作系统,要给其分配资源,当虚拟机数量增多时,操作系统本身消耗的资源势必增多;
三、容器技术
- 容器的出现:
- 容器技术提供app的打包,解决了开发者和运维人员的矛盾;
- 在开发和运维之间搭建了一个桥梁,是实现devops的最佳解决方案;
- 什么是容器:
- 对软件和其依赖的标准化打包
- 应用之间相互隔离
- 共享同一个OS kernel
- 可以运行在很多主流操作系统上
- 结构
- 和虚拟化技术的区别:容器是APP层面的隔离,虚拟化是物力资源层面的隔离
- 虚拟化+容器
- docker是容器技术的一种实现
第二章、docker环境搭建
一、mac安装linux虚拟机
- VirtualBox:一款相当强大且开源免费跨平台的虚拟机软件
- Vagrant:是一个用来构建和管理虚拟机环境的工具
二、docker machine
- Docker Machine是Docker 官方提供的一个工具,它可以帮助我们在远程的机器上安装 Docker,或者在虚拟机 host 上直接安装虚拟机并在虚拟机中安装 Docker。
三、环境搭建
第三章、docker的镜像和容器
一、docker架构和底层技术
- docker是一个平台
- docker engine
- docker architecture
- 底层技术支持
- Namespaces: 做隔离pid, net, ipc, mnt, uts
- Control groups: 做资源限制
- Union file systems: Container和image的分层
二、Docker Image概述
- 什么是image
- image的获取
- build from dockerfile
- pull from registry (docker hub)
- 镜像的发布
- 申请Docker Hub账号
- docker push [image name]:
- image的常见类型:
- 常驻内存的应用容器(如web应用)
- 一个命令行工具,可以在run的时候传入不同的参数
- 自定义一个base image
- 创建一个hello.c简单C语言程序bash
1
2
3
4
5
6
7
8
9mkdir hello-world
cd hello-world/
vim hello.c
#include<stdio.h>
int main()
{
printf("hello docker\n");
} - 编译C语言程序为二进制可执行文件bash
1
2yum install gcc glibc-static # 安装相关编译工具
gcc -static hello.c -o hello # 编译得到一个二进制可执行文件hello - 创建一个Dockerfile文件bash
1
2
3
4
5vim Dockerfile
FROM scratch # 继承自哪个镜像,scratch表示不继承其他镜像
ADD hello / # 添加hello二进制文件到根目录
CMD ["/hello"] # 命令行执行 /hello - 构建镜像bash
1
2
3
4docker build -t shengshunyan/hello-world . # -t 是给镜像一个标签; . 是指Dockerfile文件在当前目录
docker image ls # 查看image列表
docker history [image id] # 查看image的结构,image id可以在image列表中获取 - 运行bash
1
docker run shengshunyan/hello-world # 打印 hello docker,可以通过参数对容器的资源(CPU、内存等)进行限制
- 创建一个hello.c简单C语言程序
三、Docker Container
- 什么是Container
- 通过Image创建(copy)
- 在Image Layer之上建立一个container layer(可读写)
- 类比面向对象:类和实例
- Image负责app的存储和分发,Container负责运行app
- 常用命令bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15docker container ls # 查看正在运行的容器列表(docker ps是简写)
docker container ls -a # 查看所有容器列表(包括退出的容器)
docker container stop [container id] # 停止容器运行 (docker stop [container id]是简写)
docker container rm [container id] # 移除容器
docker rm $(docker ps -aq) # 移除所有暂停的容器
docker inspect [container id] # 查看容器详细信息
docker logs [container id] # 查看容器运行日志
docker run -it centos # 运行容器并不退出,进入容器
docker run -d shengshunyan/flask-hello-world # 后台运行容器
docker exec -it [docker id] /bin/bash # 进入容器,运行bash
docker # 查看docker的帮助
docker container # 查看docker container的帮助
四、Dockerfile (文档:docker doc -> reference )
- 构建自己的docker镜像
- 创建Dockerfile文件plaintext
1
2FROM centos
RUN yum install -y vim - 创建镜像bash
1
docker build -t shengshunyan/centos-vim .
- 创建Dockerfile文件
- Dockerfile语法
- FROM (尽量使用官方的image作为base image)plaintext
1
2
3FROM scratch # 制作base image
FROM centos # 使用base image
FROM ubuntu:14.04 - LABEL (帮助信息,类似注释)plaintext
1
2
3LABEL maintainer="shengshunyan@163.com"
LABEL version="1.0"
LABEL description="This is description" - RUN:为了美观复杂的RUN请用反斜线换行,避免无用的分层,合并多条命令成一行plaintext
1
2RUN yum update && yum install -y vim \
python-dev # 反斜线换行 - WORKDIR:设定当前目录,类似cdplaintext
1
2WORKDIR /root
WORKDIR /test # 如果没有会自动创建test目录 - ADD and COPY:将文件添加到容器里面,大部分情况下COPY优于ADD;添加远程文件/目录请使用curl或者wgetplaintext
1
2ADD hello / # 添加hello到根目录
ADD test.tar.gz / # 添加到根目录并解压,比COPY多一点功能 - ENV:设定环境常量plaintext
1
2ENV MYSQL_VERSION 5.6 # 设置常量
RUN apt-get install -y mysql-server="${MYSQL_VERSION}" # 应用常量 - VOLUME and EXPOSE:存储和网络
- FROM (尽量使用官方的image作为base image)
- RUN vs CMD vs ENTRYPOINT
- RUN:执行命令并创建新的Image Layer
- CMD:
- 设置容器启动后默认执行的命令和参数;
- 如果docker run指定了其他命令(比如docker run -it [docker container tag] /bin/bash),CMD命令会被忽略;
- 如果定义了多个CMD,只有最后一个会执行;
- ENTRYPOINT:
- 设置容器启动时运行的命令,让容器以应用程序或者服务的形式运行
- 不会被忽略,一定会执行
- 最佳实践:写一个shell脚本作为entrypointplaintext
1
2COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
- Shell和Exec格式
- Shell格式bash
1
2
3RUN apt-get install -y vim
CMD echo "hello docker"
ENTRYPOINT echo "hello docker" - Exec格式bash
1
2
3RUN ["apt-get", "install", "-y", "vim"]
CMD ["/bin/echo", "hello docker"]
ENTRYPOINT ["/bin/echo", "hello docker"]
- Shell格式
- 当容器作为一个命令行工具,即可以每次运行的时候传入不同的参数plaintext
1
2
3
4FROM ubuntu
RUN apt-get update && apt-get install -y stress # stress是一个测试工具
ENTRYPOINT ["/usr/bin/stress"]
CMD [] - Dockerfile实战
- 创建一个python程序python
1
2
3
4
5
6
7from flask import Flask
app = Flask(__name__)
def hello():
return "hello docker"
if __name__ == '__main__':
app.run() - 创建一个Dockerfileplaintext
1
2
3
4
5
6
7FROM python:2.7
LABEL maintainer="shengshunyan<15754600159@163.com>"
RUN pip install flask
COPY app.py /app/
WORKDIR /app
EXPOSE 5000
CMD ["python", "app.py"] - 构建镜像,并运行bash
1
2
3
4docker build -t shengshunyan/flask-hello-world .
docker run shengshunyan/flask-hello-world
# 后台运行
docker run -d shengshunyan/flask-hello-world - 构建镜像中的调试bash
1
2
3
4# 可以对中间态的镜像运行调试,进入容器查看文件夹状态
docker run -it ad82d0470bac /bin/bash
# 可以查看容器运行日志
docker logs [container id]
- 创建一个python程序
第四章、Docker的网络
一、概述
- 单机:
- Bridge Network
- Host Network
- None Network
- 多机:Overlay Network
二、网络基础回顾
- 网络的分层
- 共有IP和私有IP
- 网络地址转换NAT:将内网的私有地址转换成外部能访问的共有地址
- 网络工具
- ping:利用ICMP,验证IP的可达性
- telnet:验证服务的可用性plaintext
1
2ping 10.75.44.10
telnet 10.75.44.10 80
- 网络的命名空间
三、docker网络
- docker网络
- bridge
- none
- hostplaintext
1
2# 查看docker网络状况,type是以上三种类型
docker network inspect [type]
- 容器网络之bridge
- 容器网络之none
- 容器启动的时候设置network参数为nonebash
1
docker run -d --name test1 --network none [image name]
- 容器的服务不能从外部访问,适合存储敏感数据,只能本地通过命令行进入容器查看
- 容器启动的时候设置network参数为none
- 容器网络之host
- 容器启动的时候设置network参数为hostbash
1
docker run -d --name test1 --network host [image name]
- 容器的network namespace和host主机是一样的,不独立,可能会和主机相关端口的服务冲突
- 容器启动的时候设置network参数为host
- 多容器复杂应用的部署演示
- 启动redis服务容器bash
1
docker run -d --name redis redis # 回去拉取docker hub的redis镜像
- 创建app.py和Dockerfilepython
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20# app.py
from flask import Flask
from redis import Redis
import os
import socket
app = Flask(__name__)
# REDIS_HOST是运行容器时传入的环境变量
redis = Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379)
def hello():
redis.incr('hits')
return 'Hello Container World! I have been seen %s times and my hostname is %s.\n' % (redis.get('hits'),socket.gethostname())
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)plaintext1
2
3
4
5
6
7
8# Dockerfile
FROM python:2.7
LABEL maintaner="shengshunyan"
COPY . /app
WORKDIR /app
RUN pip install flask redis
EXPOSE 5000
CMD [ "python", "app.py" ] - 构建容器和运行bash
1
2
3
4docker build -t shengshunyan/flask-redis .
# --link 可以让app容器访问redis容器
# -e为 app容器注入环境变量
docker run -d -p 5000:5000 --link redis --name flask-redis -e REDIS_HOST=redis shengshunyan/flask-redis - 在host机上就可以测试访问bash
1
curl 127.0.0.1:5000
- 结构图
- 启动redis服务容器
- DOcker Overlay网络和etcd实现多级容器通信
第五章、Docker的持久化存储和数据共享
一、docker持久化数据
- docker持久化数据方案
- 基于本地文件系统的Volume:可以在执行Docker create或者Docker run时,通过-v参数将主机的目录作为容器的数据卷。这部分功能是基于本地文件系统的volume管理。
- 基于plugin的Volume:支持第三方的存储发难,比如NAS,aws
- Volume的类型
- 受管理的data Volume,由docker后台自动创建
- 绑定挂载的Volume,具体挂载位置可以由用户指定
二、数据持久化之Data Volume
- 利用mysql的镜像做实验bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18# 创建一个mysql容器,-v设置volume(路径和名称)
docker run -d -v mysql:/var/lib/mysql --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
# 查看volume
docker volume ls
# 进入mysql1容器中的bash,添加一个database
docker exec -it mysql1 /bin/bash
mysql -u root
create database docker;
show databases;
# 移除mysql1容器
docker rm -f mysql1
# 查看volume还是存在的
docker volume ls
# 用之前的volume创建一个新的容器mysql2,查看database,之前创建的docker database还是依旧存在
docker run -d -v mysql:/var/lib/mysql --name mysql2 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
docker exec -it mysql2 /bin/bash
mysql -u root
show databases;
三、数据持久化之Bind Mounting
- 命令bash
1
2# 容器中文件夹与host机中文件夹同步;:左边是host路径,右边是容器路径
docker run -v /home/aaa:/root/aaa - 软件开发中比较常用,在容器外更新更新app相关文件即可同步容器中的服务;
第六章、Docker compose多容器部署
一、Docker compose是什么
- 对多个docker容器进行批处理的需求
- docker compose是一个工具,这个工具可以通过一个yml文件定义多容器的docker应用,通过一条命令就可以根据yml文件的定义去创建或管理这多个容器
二、Docker compose管理wordpress多容器的示例
- Docker compose需要翻墙安装
- yml文件plaintext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32version: '3'
services:
wordpress:
image: wordpress
ports:
- 8080:80
depends_on:
- mysql
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_PASSWORD: root
networks:
- my-bridge
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: wordpress
volumes:
- mysql-data:/var/lib/mysql
networks:
- my-bridge
volumes:
mysql-data:
networks:
my-bridge:
driver: bridge - docker-compose的一些常用命令
- docker-compose负载均衡
- 启动五个web服务:docker-compose up –scale [service name]=5 -d
- haproxy做代理
第七章、容器编排Docker swarm
一、swarm mode
二、为什么需要容器编排
- 管理很多容器
- 方便的横向拓展
- 容器如果down了,可以自动恢复
- 不影响业务的情况下更新容器
- 监控追踪容器
- 调度容器的创建
- 保护隐私数据
三、创建一个三节点的swarm集群
- 三个主机(manager, work1, work2)(可以用虚拟机创建)
- 初始化swarm集群,设置管理节点:docker swarm init –advertise-addr=[manager ip]
- 添加work节点,进入work类型的主机(work1,work2),执行相关命令(命令是上一步初始化的输出)
四、service的创建维护和水平拓展
- 创建servicebash
1
2
3
4
5docker service create --name demo busybox sh -c "while true;do sleep 3600;done"
# 查看service
docker service ls
# 查看service创建的容器运行在哪个节点
service ps demo - 水平拓展bash
1
2docker service scale demo=5
# 5个容器运行,一个容器down了,可自动恢复 - 删除servicebash
1
docker service rm demo
五、集群服务间通信之Routing Mesh
- Internal: container和container之间的访问通过overlay网络(通过虚拟IP)
- Ingress: 如果服务有绑定接口,则此服务可以通过任意swarm节点的相应接口访问
六、docker stack
- docker stack简介:单机模式下,我们可以使用 Docker Compose 来编排多个服务,而 Docker Swarm 只能实现对单个服务的简单部署。本文的主角 Docker Stack ,通过 Docker Stack 我们只需对已有的 docker-compose.yml 配置文件稍加改造就可以完成 Docker 集群环境下的多服务编排
- docker compose.yml文件plaintext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47version: '3'
services:
web:
image: wordpress
ports:
- 8080:80
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_PASSWORD: root
networks:
- my-network
depends_on:
- mysql
deploy:
mode: replicated
replicas: 3
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
update_config:
parallelism: 1
delay: 10s
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: wordpress
volumes:
- mysql-data:/var/lib/mysql
networks:
- my-network
deploy:
mode: global
placement:
constraints:
- node.role == manager
volumes:
mysql-data:
networks:
my-network:
driver: overlay - 在manager节点部署服务,docker stack deploy example –compose-file=docker-compose.yml
- 访问8080端口可以查看节点可视化页面
七、docker secret管理和使用
- secret包括:用户名密码、SSH Key、TLS认证、不想让别人看到的数据
- secret management:
- 存在swarm manager节点raft database里
- secret可以assign给一个service,这个service就可以看到secret
- 在container内部,secret看起来像文件,但实际是在内存中
八、service更新
- 当service的容器个数(scale的值)> 1时,就可以不中断服务得更新
- 更新servuce:docker service update –image [new image name] [service name]
第八章、DevOps初体验-docker cloud
一、docker cloud
第九章、容器编排Kubernetes
一、Kubernetes简介
- 结构图
- 简介:kubernetes,简称K8s,是用8代替8个字符“ubernete”而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes提供了应用部署,规划,更新,维护的一种机制。
二、K8S最小调度单位Pod
- 一个Pod包含一个或多个Container
- Pod内部共享命名空间
- Pod建立、对外暴露服务端口
- Pod横向拓展,创建多个Pod
三、deployment
- 简介:
- deployment 是用来管理无状态应用的,面向的集群的管理,而不是面向的是一个不可变的个体,举例:有一群鸭子,要吃掉一个,只需要再放一个新的鸭仔就好了,不会影响什么,而有状态的应用,就同时养三条狗一样,而每个狗都是无法代替用新的事物代替的,因为有“感情”这个状态在里面
- Deployment 为Pod 和 ReplicaSet 之上,提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController 来方便的管理应用。你只需要在 Deployment 中描述您想要的目标状态是什么,Deployment controller 就会帮您将 Pod 和ReplicaSet 的实际状态改变到您的目标状态。您可以定义一个全新的 Deployment 来
四、多节点K8S集群
五、service
- 不要直接使用和管理Pods,在更新或者做拓展的时候,Pods有可能被terminated
- service简介
- kubectl expose命令,会给Pods创建一个service,供外部访问
- service有三种类型:clusterIP,NodePort,外部的loadBalancer
- 另外也可以使用DNS,但需要DNS的add-on
第十章、Kubernetes简介和安装
一、Kubernetes安装
- minikube:可以在本地搭建一个开发测试的环境,只有一个节点
- kubeadm:在本地搭建一个k8s的集群
- 在云服务商搭建k8s集群
第十一章、Kubernetes中的基本概念和操作
一、Kubectl的基本使用
bash
1 | # 获取集群节点信息 |
二、k8s的节点和标签
- 节点bash
1
2# 查看节点详情
kubectl describe node [node name] - 标签bash
1
2
3
4
5
6
7# 查看节点标签
kubectl get node --show-labels
# 添加label
kubectl label node [node name] [label]
kubectl label node k8s-master env=test # 示例
# 删除label
kubectl label node k8s-master env- - roles:可通过添加label的方式添加
三、k8s的最小调度单位pod
- pod
- pod的创建:.yml文件
- pod的操作bash
1
2
3
4
5
6
7
8
9
10
11
12# pod创建
kubectl create -f nginx_busybox.yml
# 查看pod
kubectl get pods
kubectl get pods -o wide
# 获取pod详细信息
kubectl describe pod [pod name]
# 进入pod的容器
kubectl exec [pod name] -it sh # 默认进入第一个容器
kubectl exec [pod name] -c [container name] -it sh # 可指定容器
# 删除pod
kubectl delete -f nginx_busybox.yml
四、命名空间namespace
- 在不同的命名空间中,各种资源的名字是相互独立,比如可以具有相同名称的pod存在
- namespace操作bash
1
2
3
4# 创建namespace
kubectl create namespace [space name]
# 查询全部pod
kubectl get pod --all-namespaces
五、context
- 可以改变当前使用的默认namespace,默认是default
六、controller和deployment
- deployment和控制器模型:
- 定义一组Pod期望数量,Controller会维持Pod数量与期望数量一致
- 配置Pod的发布方式,controller会按照给定的策略更新Pod,保证更新过程中不可用Pod维持在限定数量范围内
- 如果发布有问题支持回滚
- deployment是一种期望状态go
1
2
3
4
5
6
7
8
9for {
实际状态 := 获取集群中对象X的实际状态
期望状态 := 获取集群中对象X的期望状态
if 实际状态 == 期望状态 {
什么都不做
} else {
执行编排动作,将实际状态调整为期望状态
}
} - deployment操作bash
1
2
3
4
5
6
7
8# 创建deployment
kubectl create -f nginx_deployment.yml
# 查询deployment
kubectl get deployment
# 更新deployment
kubectl apply -f nginx_update.yml
# 回滚
kubectl rollout undo deployment [deployment name] ...
第十二章、容器的运维和监控
一、容器的基本监控
- 命令行查看bash
1
2
3
4
5
6# 查看后台容器情况
docker ps
# 查看容器内部运行的进程
docker top [container id]
# 查看容器占用系统的资源
docker stats - docker监控工具:weavescope
二、k8s集群
- k8s集群运行资源监控工具:heapster
- 根据资源占用自动横向伸缩
- 集群log的采集和展示——ELK + Fluentd
- 集群监控方案:prometheus
第十三章、decker + DevOps实战
详细内容独立记在笔记《利用Gitlab CICD实现前端资源自动部署》中