Docker
…
Docker 准备工作
Docker Playground
这是一个不用下载的,在线就可以用的Docker。使用需要使用Docker的账号密码,可以去注册一个。
下载 Docker (已弃用)
Docker分为社区版和企业版。这里主要介绍社区版。
进入官方DockerToolbox下载页面,按照安装教程安装Docker Toolbox。
国内阿里云[DockerToolBox下载页面]
(http://mirrors.aliyun.com/docker-toolbox/windows/docker-toolbox/DockerToolbox-18.03.0-ce.exe),如果官方的速度太慢,可以切换到这里。这里的Docker不是最新版的。
其他下载页面,包含Ubuntu下的一键安装脚本。
安装过程会自动安装VirtualBox,Dokcer,Docker-compose以及Kitematic。
Docker 容器查询
Docker 官方文档
W3C Docker 参考文档
下载 Docker
Windows 10及以上版本可以到官网下载。安装前需要先安装相关组件,在控制面板->程序->程序和功能->启用和关闭Windows功能
中安装适用于Linux的Windows子系统
,安装完成后再安装WSL2升级包。安装完成后再安装Docker即可。
Linux系统安装过程更为简单,只需要执行下面的命令即可。
1 | curl -sSL https://get.docker.com | sh |
Docker Compose安装:到Github上下载二进制包,添加到环境变量中即可。
配置 Docker
使用Docker,Docker会默认为我们创建一个虚拟机,下载的Image也都会存储在虚拟机中。默认情况下,虚拟机会存储在用户文档下的.docker
目录下。若想改变虚拟机默认存储,可以配置环境变量MACHINE_STORAGE_PATH
即可。
(如果遇到Waiting for an IP无限等待,可能是OpenSSH的问题,这个是Win10上内置的功能)
运行桌面上的Docker Quickstart Terminal
,首次启动Docker会为我们创建一台虚拟机,并在这个虚拟机目录下创建配置文件。打开配置文件(如果修改过就去改后的目录找):
1 | C:\Users\用户名\.docker\machine\machines\default\config.json |
在HostOptions
->EngineOptions
->RegistryMirror
中配置为:
1 | { |
新版本为:上方的设置按钮,Docker Engine
中配置。
此处的镜像地址最好是到阿里云找一个。登录阿里云,点击产品与服务,选择容器镜像服务->镜像中心->镜像加速器。
配置完成后,重新运行桌面上的Docker Quickstart Terminal
。
首次使用 Docker
首先进入Docker Quickstart Terminal
后,在项目目录执行如下内容,用来测试docker是否正常。
1 | docker run ubuntu:16.04 /bin/echo "Hello world" |
提示Hello World说明配置成功。
Docker 安装了什么
安装完成后,我们来简单梳理一下都做了什么。
Docker在我们的电脑上安装了:
- VirtualBox:虚拟机工具。
- Docker Machine:虚拟机管理工具。
- Docker Compose:Docker脚本执行工具。
- Docker Client
完成安装后,首次运行Docker Quickstart Terminal
,Docker就会创建一个虚拟机,作为我们的Docker Server,而我们的本地系统则成为了Docker Client。
之后我们使用的容器将全部运行在这个虚拟机中。查看虚拟机的IP可以使用命令:
1 | docker-machine env |
Ubuntu 下的 Docker
如果图个方便,那么直接安装:
1 | sudo apt-get install -y docker.io containerd runc docker-compose |
如果想去官方下载最新版,那么可以按照官方的程序来一遍。
按照官网给出的安装方法安装Docker。此外,官网还给出了下载Docker包安装和卸载Docker的方法。
1 | # 首先删除旧版本 |
修改Docker配置文件:
在/etc/docker/daemon.json中增加如下内容:
1 | { |
此处的镜像地址最好是到阿里云找一个。登录阿里云,点击产品与服务,选择容器镜像服务->镜像中心->镜像加速器。
Ubuntu 快速安装指南
1 | curl -sSL https://get.docker.com | sh # 一键安装 |
配置VS Code
远程开发,修改/lib/systemd/system/docker.service
文件
1 | ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375 |
再重新加载Docker
1 | sudo systemctl daemon-reload # 加载阿里云加速镜像 |
VS Code
安装docker
插件,打开配置,输入docker:host
,编辑host
。
下载Docker Cli,加入到环境变量中。
在任务管理器->服务->右键->打开服务
中启动SSH Agent
服务(OpenSSH Authentication Agent)。
1 | get-service ssh* # 查看服务状态 |
在本地主机上配置SSH,生成公钥id_rsa.pub
和私钥id_rsa
。
1 | ssh-keygen |
公钥放到远程主机上,追加到~/.ssh/authorized_keys
文件中。
本地执行命令,添加私钥。
1 | ssh-add id_rsa |
配置本地Docker的Context
1 | docker context create context_name --docker "host=ssh://user@host" |
GPU 支持
如果要安装Docker的GPU支持,可以下载该模块。实现GPU支持后,可以使用Tensorflow-GPU的Docker。
Docker 原理与架构
Docker 是一个平台,它通过Docker Engine把底层的设备与上层应用隔离开。Docker Engine是一个后台进程,即是一个REST API Server,它还有一个CLI接口(docker)。
Docker 包含 Client 与 Server 。Docker Client 通过命令方式控制 Docker Server,在Server上操作Container,Image等。Docker Server通过代码仓库或Docker Hub获取Docker镜像。
Docker Image
Image 本身是只读的。Docker搭建的应用的过程就是将几个Image一层一层叠加上去的过程。例如在Ubuntu Image层上叠加Apache Image层,在上面再叠加一个PHP Image层,就可以实现一个网站。Image之间可以共享同一层,例如Apache与MySQL可以在同一层上。
使用 Image
1 | # 查看 image |
如果要查询Image,可以去Docker Hub上查找。
创建 Image
如果想要自己创建一个Base Image,可以这样做。
例如我们编写一个 c 程序。
1 | vim main.c |
编辑程序代码:
1 |
|
编译程序:
1 | gcc -static main.c -o main |
执行程序查看效果:
1 | ./main |
编写Dockerfile文件:
1 | vim Dockerfile |
1 | # scratch 表示没有Base |
构建运行Image:
1 | # 构建 |
删除 Image
删除Image:
1 | docker image rm image_id |
Docker Container
Container 是一种可读可写的层。我们在运行一个Image时,Docker会在这个Image上添加Container层,用于读写程序运行时产生的数据。
我们也可以把Container与Image类比成对象和类。Image只读,负责存储app,可以当做是一个类;Container则是负责运行app,可以当做是一个对象。
使用 Container
运行一个Image,就创建了一个Container。Container在运行完成后就会退出。
1 | docker run ubuntu |
运行完成后:
1 | # 查看所有容器,-a 表示包括已经结束运行的 |
使用如下命令可以进入容器内做交互,注意,这里的所有数据会在Container结束运行时消失:
1 | # -i 表示交互 -t 表示标准输入输出 |
删除Container:
1 | docker container rm container_id |
当我们在container中产了数据,做了某些操作,我们就可以通过commit方式将修改后的contianer变为image。
从Container创建Image
1 | docker container commit # 同docker commit |
我们也可以从Dockerfile创建container。首先创建一个空的目录,这个目录下的除配置文件外的所有文件将会被打包进入image。我们创建一个配置文件Dockerfile:
1 | FROM ubuntu |
执行命令打包:
1 | docker container build # 同 docker build |
进入运行中的container:
1 | # 进入命令行 |
停止container:
1 | docker stop container_id |
运行时给container命名:
1 | docker run -d --name=demo image_name |
这样就可以不用再操作container_id了,而是可以直接操作name。
查看container信息:
1 | docker inspect container_id |
查看container输出信息:
1 | docker logs container_id |
上传自制 Image
首先注册登录Docker,并进入Docker Hub。
在本地命令行:
1 | # 登录账号 |
进入Docker Hub就可以看见自己推送的Image了。
也可以让Docker与Github关联。在Docker页面,Create,Create Automated Build里面,选择Link Accounts关联Github。在Github里创建Repository,将Dockerfile上传到代码仓库。Docker的服务器会帮我们Build镜像。
如果要搭建自己的Image仓库,可以在Docker hub里面搜索registry,按照里面的教程操作即可。
打包一个Python程序到Image
创建一个Python脚本
首先创建Docker打包目录,在目录下创建文件app.py
:
1 | from flask import Flask |
创建一个 Dockerfile
再创建Dockerfile:
1 | FROM python:2.7 |
创建 Image
1 | docker build -t author/image_name . |
如果创建失败,遇到bug想要调试,可以查看build日志,找到最后一个创建成功的Step,复制其id,并通过命令进入bash环境:
1 | docker run -it id /bin/bash |
Docker 压力测试
进入docker容器中:
1 | docker run -it ubuntu |
安装stress工具:
1 | sudo apt-get update && sudo apt-get install -y stress |
使用stress:
1 | # vm Worker数 |
或使用Dockerfile
1 | FROM ubuntu |
1 | docker build -t image_tag . |
创建一个常开的Container
使用busybox这个Image,可以创建一个常开的Container:
1 | docker run -d --name test busybox /bin/sh -c "while true; do sleep 3600; done" |
限制Container资源
在开启Container时,可以通过添加参数限制Container的资源,包括cpu个数,内存大小等:
1 | # --memory 内存 --cpu-shares cpu相对占用 |
Docker Network
单机Network有三种模式:
- Bridge Network
- Host Network
- None Netw
多机Network有 Overlay Network。
手工配置 Linux Network 命名空间
Network命名空间(Namespace)是一种虚拟化技术,它可以将一个物理机虚拟化成多个虚拟机。一个命名空间相当于一个虚拟主机。我们可以通过配置命名空间下的虚拟端口,可以完成虚拟机,也就是命名空间中的网络连接。这也是docker容器的底层技术。
Linux的Network命名空间有关命令:
1 | # 查看所有命名空间 |
配置虚拟网络的过程如下:
1 | # veth即为端口,首先创建一对连起来的端口 |
Bridge Network
Bridge Network 原理探索
查看Linux本机IP:
1 | ifconfig |
可以看到docker0网桥,veth453e607端口以及其他的网络设备。其中:
- docker0:是一个网桥,是Docker服务端上用于连接其他设备的端口。
- veth…:是Docker Container上的端口。它是成对出现的,而它的另一端连接到docker0上。
可以使用下面的工具查看这个拓扑结构。
1 | sudo apt-get install -y bridge-utils |
Bridge Network 使用
查看所有的Docker网络:
1 | docker network ls |
我们这里创建两个容器,并让第二个通过桥接方式连接到第一个容器上。
1 | docker run -d --name test1 busybox /bin/sh -c "while true; do sleep 3600; done" |
这样test2就可以直接通过hostname访问test1,但是test1无法通过hostname访问test1。但是二者可以通过IP访问。
另外,我们也可以通过network方式连接两个容器。创建好的容器默认连接到bridge上。我们新建一个bridge,并让两个容器联入新的bridge。
1 | # 创建网桥 |
之后,我们还要将端口映射出来。
新建一个Nginx服务器用于测试。
1 | # 将本地8030端口映射到容器的80端口 |
访问本地8030端口即可查看。
Host Network
Host网络是与主机共享一个Network命名空间。启动一个连接Host网络的容器:
1 | docker run -d --name test4 --network host busybox /bin/sh -c "while true; do sleep 3600; done" |
这样的容器将直接使用主机上的端口工作。
None Network
None网络是一个孤立网络。启动一个连接None网络的容器:
1 | docker run -d --name test6 --network none busybox /bin/sh -c "while true; do sleep 3600; done" |
这个容器将不接入任何网络。
Overlay Network
通过Overlay Network可以实现不同物理机上的Docker容器通信,Docker通过VXLAN技术实现了Docker容器在不同物理机上的通信。这里可以使用etcd实现分布式存储,用于辅助Overlay网络。
使用方法:
1 | docker network create -d overlay network_name |
这样不论在哪个物理机上操作Docker,都操作的是同一个服务,也就是两台物理机上使用的同一个Docker。
Docker 数据持久化
Data Volume
Volume有两种,一种是作为本地文件存储的Volume,另一种是通过第三方插件,如NAS,AWS等。
创建的Volume有两种,一种是作为Docker对象呈现,可以用命令查看:
1 | docker volume ls |
另一种是直接挂在到本地目录。
对于前者,首先使用Dockerfile定义Volume:
1 | VOLUME ["/var/lib/mysql"] |
创建的时候再指定参数:
1 | docker run -d --name mysql_test -v mysql:/var/lib/mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql |
Bind Mouting
这种模式不必创建Volume,而是可以直接使用,也就是将目录挂载到本地,实现目录的同步:
1 | docker run -v /home/aaa:/root/aaa |
Docker Compose
Docker Compose可以通过脚本快速搭建容器集群,适用于开发环境。
一个例子
1 | docker run -d --name mysql-test -v mysql-data:/var/lib/mysql \ |
常用命令
1 |
|
简介
Docker Compose相当于一个批处理工具,可以定义,管理多个docker应用。
Docker Compse有三大概念:
- Services:代表一个容器,可以指定Network和Volume。
- Network:
- Volumes:
使用方法
1 | version: "3" |
1 | # 启动一个脚本 |
弹性伸缩
当我们需要做负载均衡时,可以使用伸缩的功能创建多个Web服务器,并用redis来存储客户的sessions。我们可以设计如下的架构:
负载均衡器 $
\begin{Bmatrix}
Web服务 1 \
Web服务 2 \
Web服务 3 \
\end{Bmatrix}
$Redis数据库
命令行方式创建多个服务:
1 | docker-compose up --scale service_name=3 -d |
使用脚本方式创建负载均衡器,多个Web服务,以及Redis数据库:
1 | version: "3" |
启用脚本:
1 | docker-compose up |
将web服务增加到3个:
1 | docker-compose up --scale web=3 -d |
环境变量
环境变量:在同一目录里下建立.env
文件,用于设置环境变量。在docker-compose.yml
中启用环境变量如下:
1 | services: |
查看一个服务使用了哪些环境变量
1 | docker-compose run web env |
内置环境变量
1 | COMPOSE_PROJECT_NAME |
预设与多模块
如果想要给docker-compose.yml
配置不同环境下,启动不同的容器的设置,可以使用profile
。
1 | version: "3.9" |
当启动容器时,指定profile
,就可以开启特定的几个服务。
1 | docker-compose --profile frontend --profile debug up |
默认情况下,Compose会读取两个文件:docker-compose.yml
和docker-compose.override.yml
,同时合并两个文件的结果。如果有其他文件,可以用-f
来合并每个文件。
1 | docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d |
网络
每一个Compose对应一个网络。同一个Compose下的容器可以通过容器名互相访问。
也可以使用Links为被连接的容器起别名。
1 | version: "3.9" |
也可以使用多网络,更改网络驱动,连接外部网络等。
1 | version: "3.9" |
控制启动顺序
启动顺序由depends_on
,links
,volumes_from
,network_mode: "service:..."
决定。
depends_on:当依赖容器启动后再启动自己。
Docker Swarm
Docker Swarm可以快速搭建容器集群,适用于生产环境。在生产环境中,为了保障服务的正常使用,我们决不能停止当前的服务。不仅如此,我们还需要实时监控服务的状态,甚至在宕机时能够自动恢复。另外,服务还要有足够的安全性,防止数据泄露,扛得住网络攻击。
Swarm 架构
在Swarm中有两种角色。一种是Worker,一种是Manager。Manager是管理Worker的节点,可以有多个,且他们之间数据可以同步,同步使用Raft,。Worker是处理数据的节点,也可以有多个,他们之间通过Gossip network通信。
在Swarm中还定义了Service与Replicas。Service代表了一种服务,而Replicas则是服务下属的节点,一个服务可以有多个下属的节点。每一个Replica是一个容器。
创建集群
首先创建三台虚拟机,命名为Manager,Worker1,Worker2。
1 | # 创建虚拟机 |
在Manager节点上执行:
1 | docker swarm init --advertise-addr=192.168.205.10 |
之后会返回一条指令,这条指令是给要加入Manager的Worker节点使用的:
1 | docker swarm join --token SWMTKN-1-3cv6sadfwe...asfwef 192.168.205.10:2377 |
进入Worker1节点,执行刚刚得到的指令,即可加入集群。
在Manager节点可以查看Worker情况:
1 | docker node ls |
横向扩展
横向扩展是指通过创建多个服务来做负载均衡,以保证服务的可靠性。依然是上面的三个虚拟机的集群,在Manager上搭建服务:
1 | docker service create --name demo busyBox sh -c "while true; do sleep 3600; done" |
查看刚刚搭建的服务:
1 | docker service ps demo |
可以看到一个REPLICAS属性,这个属性就是扩展的节点数。下面我们扩展这个服务:
1 | docker service scale demo=5 |
再次查看操作结果:
1 | docker service ps demo |
会发现5个服务被平均分配到3台虚拟机上了。如果某个服务宕机了,Swarm会自动新建一个节点,修复集群。
停止服务:
1 | docker service rm demo |
在线更新
为了保证更新过程,服务不宕机,Swarm提供了动态更新的功能。
首先创建一个overlay网络:
1 | docker network create -d overlay demo |
在这个网络上创建一个服务,这个服务是一个旧版的Nginx,一会我们通过动态更新换为最新版Nginx。更新之前,首先保证服务节点数大于一个:
1 | docker service create --name web --publish 8080:5000 --network demo nginx:1.16.1 |
更新Image:
1 | docker service update --image nginx:latest web |
更新端口:
1 | docker service update --publish-rm 8080:5000 --publish-add 8088:5000 web |
在更新过程中,会有旧版和新版同时服务的状况。
搭建WordPress
使用WordPress,需要有WordPress和MySQL两个服务。
首先在Manager节点,创建Overlay网络:
1 | docker network create -d overlay demo |
创建服务:
1 | docker service create --name mysql \ |
之后三个节点的IP地址都可以访问WordPress服务了。
DNS 服务
在Docker内部拥有一个DNS服务,这个服务维护了每一个服务以及其服务IP。如果这个服务有3个节点,那么这个服务就会另外有3个IP,对应3个容器的IP。也就是说,这个服务一共有4个IP:1个虚拟的IP用于对外提供服务,这个IP会保持不变;另外还有3个用于对应容器,可以随时扩展收缩。
我们可以通过访问虚拟机集群,不论访问哪个虚拟机的IP,都能访问容器中的服务。在这个过程中,Docker DNS会自动为我们寻找需要的服务和它的虚拟IP。但是我们请求这个服务,最终会看到容器所在的虚拟机的主机名。
对比Docker Overlay网络,Overlay实现了多个虚拟机之间的容器通信,使用的技术是VXLAN Tunnel;而服务之间则是通过虚拟IP,基于Docker DNS通信,使用LVS(Linux Virtual Server)技术。
使用 Stack 通过 Docker Compose 部署服务
使用Stack通过Docker Compose更新服务,首先要确保image不能是在本脚本build,而是必须使用已经build好的image。
deploy属性指定了更新的策略,包括部署数量,部署方式等。
1 | version: "3" |
使用docker compose脚本搭建的集群,需要脚本中包含deploy属性,并使用docker stack使用与更新服务:
1 | # 部署服务 |
最后删除服务:
1 | docker stack rm example |
另外推荐一个服务visualizer
,可以可视化查看集群中每个虚拟机上的容器状况。
如果更新服务,可以直接修改docker compose文件,然后重新部署:
1 | docker stack deploy example --compose-file=docker-compose.yml |
Secret 管理
在生产环境中,用于管理系统的密码一般不会明文写到docker compose中,而是使用一些手段隐藏起来。
因此用到Secret管理。这里的Secret管理主要包括:
- 用户名/密码
- SSH Key
- TLS 认证
- 机密数据
在Manager节点中,有一个内置的分布式存储。在这个存储中我们就可以存储我们的Secret。当Worker上有容器想要使用时,就可以请求分布式存储获取Secret。
首先创建一个文件password.txt
,将我们的密码写到这个文件中。创建一个Secret:
1 | docker secret create demo-password password.txt |
之后删掉password.txt
。
查看创建的Secret:
1 | docker secret ls |
不创建文件而直接创建Secret也可以,通过管道的方式即可:
1 | echo "admin123456" | docker secret create demo-password2 |
删除Secret可以:
1 | docker secret rm demo-password2 |
使用Secret:
1 | docker service create --name client --secret demo-secret busybox sh -c "while true;do sleep 3600;done" |
在容器的/run/secrets/
下可以看到刚刚的secret,是可以看到密码原文的。在MySQL中,可以使用MYSQL_ROOT_PASSWORD_FILE
指定密码文件。
在compose中也可以使用Secret。
1 | version: "3" |
Docker 开发
系统镜像
BusyBox
包含常用命令,体积小于2MB。
1 | docker pull busybox |
Alpine
面向安全的轻型Linux发行版,大小仅5MB左右,还包括了APK包管理器。
1 | docker run alpine /bin/bash |
包管理器使用:
1 | apk add --no-cache <package> |
包名可以到该网站查阅。
Debian / Ubuntu
非常适合研发场景,支持多种计算机系统结构。
1 | docker run -it debian bash |
另外还有 CentOS Fedora 等。
添加SSH服务
使用Commit创建
1 | docker run -it ubuntu |
使用Dockerfile创建
1 | # 创建工作目录 |
Web 服务
Apache
官方Apache不带PHP,如果需要,可以到该网站查询: 7.0.7-apache
编写Dockerfile
1 | FROM httpd:2.4 |
编译镜像
1 | docker build -t apache2-image . |
基于 Ubuntu Debian 的配置
1 | # 时区 |
Nginx
使用 Docker-compose
1 | web: |
针对Nginx服务器的内核优化命令
1 | kernel.sysrq = 0 |
Tomcat
实现 Servlet 和 JSP 支持。
Jetty
实现 Servlet 支持。
LAMP
- linode/lamp
- tutum/lamp
持续开发与管理
CI : 持续集成;CD : 持续交付
Jenkins
1 | docker run -p "8000:8080" -p "50000:50000" -v ~/home:/var/jenkins_home jenkins |
GitLab
1 | docker run ... |
数据库
MySQL
应用广泛。
查看日志
1 | docker logs mysql_name |
自定义配置文件
1 | # 编辑此配置目录 /etc/mysql/conf.d |
脱离cnf文件进行配置
1 | # 通过标签flags传递配置选项 |
Oracle Database XE
免费,体机小,配置简单。适用于PHP,JAVA,.NET等。
MongoDB
一种NoSQL,并提供关系型数据库的绝大部分功能。
Redis
基于内存的数据结构存储系统,用作缓存和消息中间件。
Cassandra
开源分布式数据库,支持Spark,Storm,Hadoop系统集成,类似与HBase。
分布式处理与大数据平台
常见工具:
- Hadoop
- Spark
- Storm
- Elasticsearch
Hadoop
sequenceiq/hadoop-docker:2.7.0
1 | docker run -it sequenceiq/hadoop-docker:2.7.0 /etc/bootstrap.sh -bash |
Spark
sequenceiq/spark:1.6.0
基于Scala开发的大数据处理框架。与Hadoop不同的是,Hadoop将数据存储到硬盘上,而Spark存储到内存中。
Spark支持SQL查询,流处理,机器学习(Spark MLlib),图处理(Spark GraphX)等。支持Scala,Java,Python,Cljure,R等。
还提供其他库,在大数据分析和机器学习领域提供更多功能。
Storm
baqend/storm:3.4.8
baqend/storm:1.0.0
1 | git clone https://github.com/denverdino/docker-storm.git |
在Hadoop上加入了实时运算的特性,可以实时处理大数据流。不同于Hadoop和Spark,Storm不进行数据的收集和存储工作,它直接通过网络实时的接受数据并且实时的处理数据,然后直接通过网络实时的传回结果。
Elasticsearch
基于Lucene的开源搜索服务,支持RESTful Web接口。支持实时分布式数据存储和分析查询功能。
编程开发
C / C++
- GCC: GNU 开发,跨平台编译器的标准。
- LLVM: Low Level Virtual Machine,提供了一套中立的中间代码和编译基础设施,使得优化可以在编译,连接,运行环境中。
1
docker pull imiell/llvm
- Clang: 基于LLVM的编译器,兼容GCC并准备超过GCC。特性是快,内存占用小,诊断信息可读性强,模块化设计。
1
docker pull bowery/clang
Java
- OpenJDK: 支持JavaSE。
- Spring Boot: 为了简化Spring应用搭建过程,内嵌Tomcat,Jetty,Undertow,提供starter POM,简化Maven配置,无需XML配置。
1
git clone https://github.com/spring-guides/gs-spring-boot-docker.git
Python
- PyPy: Python实现的Python解释器和即时编译工具,与CPython完全兼容。可以将Python运行速率提高10倍。
- Flask
Javascript
- NodeJS: 运行于服务端,采用事件驱动模型,提供多种系统级API。
Golang
1 | go get github.com/golang/example/outyet |
Linux 命名空间
进程命名空间:
- 同一进程,在不同空间下看到的进程号不同。
- 子空间的进程对父空间可见。
- 容器只能看到docker-containerd进程及以下的进程。
IPC 命名空间:
- IPC是Linux进程间交互方法:包括信号量,消息队列,共享内存等。
- 同一IPC命名空间的进程可以彼此交互。
网络命名空间:
- 提供完全独立的网络协议栈:网络设备接口,IPv4,IPv6,路由表,防火墙规则,sockets等。
- 网络命名空间之间通过虚拟网卡连接。
挂载命名空间:
- 可以将一个进程的根文件系统限制在某一个目录下。
- 类似与chroot。
UTS命名空间:
- 允许每个容器拥有独立的主机名和域名。
- Docker默认指定ID前六字节为主机名。
用户命名空间:
- 一个进程在某个用户命名空间内的用户和组 ID 可以与用户命名空间外的不同。
- 进程在一个用户命名空间外没有特权,但在这个用户命名空间内有 root 特权。
控制组:
- 用来对内核资源进行隔离,限制,审计等。
- 可以限制资源(最大内存),设置优先级,资源审计,隔离,控制等。
Linux 网络虚拟化
运维与监控
Docker 命令行查看
查看容器内状况:
1 | docker top container_id |
查看节点所有容器情况:
1 | docker stats |
WeaveScope
安装过程:
1 | sudo curl -L git.io/scope -o /usr/local/bin/scope |
打开4040端口的页面,即可看到WeaveScope。通过这个页面,我们可以可视化管理容器。
添加其他节点到监控中,要在两个节点都执行:
1 | scope launch node_1_ip node_2_ip |
DevOps
推荐工具:
- 代码管理
- Github
- Gitlab
- 码云
- bitbucket
- 代码持续集成
- TravisCI
- GitlabCI
- Jenkins
- 代码测试与检查
- Codecov
- SonarQube
GitLab
Ubuntu 安装 Gitlab
首先开一台虚拟机,用于安装Gitlab(配置要求:推荐4GB内存):
1 | # 安装必要扩展程序 |
下载Gitlab:
安装官方版本:
1 | curl -s https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash |
安装国内镜像版本(仅限Ubuntu 16.04):
在文件/etc/apt/sources.list.d/gitlab-ce.list
中写入:
1 | deb https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/ubuntu xenial main |
再安装Gitlab:
1 | # 配置GPG公钥 |
安装完成后配置GitLab:
1 | # 配置GitLab |
安装完毕后,首次登陆需要设置密码。
配置GitLab,可以到/etc/gitlab/gitlab.rb
文件中:
1 | # URL |
修改完成后,让配置生效:
1 | sudo gitlab-ctl reconfigure |
GitLab CI/CD
CI是代码持续化工具,可以在代码提交后自动化执行代码风格检查,单元测试,项目编译等。当然也可以用Jenkins代替。
安装 Runner
另开一台虚拟机,首先安装Docker:
1 | curl -sSL https://get.docker.com/ | sh |
安装Gitlab CI Runner:
1 | curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.rpm.sh | sudo bash |
检查是否安装成功:
1 | sudo gitlab-ci-multi-runner status |
设置Docker权限:
1 | sudo gpasswd -a gitlab-runner docker |
注册Runner:
1 | sudo gitlab-ci-multi-runner register |
查看Runner:
1 | sudo gitlab-ci-multi-runner list |
回到Gitlab页面,可以看到runner settings里面多了一个runner。
使用 Runner
一个项目要使用Runner,首先需要在项目下建立文件.gitlab-ci.yml
。进入一个项目,选择CI/CD->Pipeline。这时可以看到一个Pipeline。每次提交代码,Pipeline就会自动执行一次,且每一个Stage顺次执行。
使用CI/CD可以自动化执行测试、编译、部署等步骤。
1 | # .gitlab-ci.yml |
检查代码风格
首先注册一个Docker类型的Runner:
1 | sudo gitlab-ci-multi-runner register |
提前把Image拉取到本地:
1 | docker pull python:3.7 |
在项目中加入:
1 | # .gitlab-ci.yml |
自动化部署
CD是持续化部署,即在原来的基础上再进行项目部署。例如有一个项目,经过代码检查后做部署:
1 | # .gitlab-ci.yml |
如果风格检查不能通过的话,部署是无法进行的。
另外,为了不让用户每一次push代码都触发一次CI/CD,我们可以把master分支锁定住,防止任何人提交。任何人必须在分支中改动。
在Gitlab中配置:
Repository->Protected Branches->master分支->Allowed to push 改为No one。
General->Merge request settings->Only allow merge requests to be merged if the pipeline succeeds.
用户在提交代码后,进入Gitlab平台,填写Merge Request,等待Pipeline通过。
管理员用户在收到Merge Requst后,则可以执行Merge操作,部署将自动执行。
版本发布
首先搭建一个Docker Registry,类似于Docker Hub。
这里创建第三个服务器,作为Docker Host。首先安装Docker,然后执行:
1 | docker run -d -v /opt/registry:/var/lib/registry -p 5000:5000 --restart=always --name registry registry:2 |
回到Gitlab-CI服务器上,编辑/etc/docker/daemon.json
文件:
1 | { |
重启Gitlab-CI服务器上的Docker服务:
1 | sudo systemctl daemon-reload |
再从Docker Hub拉取一个镜像:
1 | # 拉取busybox |
再Push到我们的私有仓库:
1 | docker push Docker_Registry_IP:5000/busybox |
如果这些步骤成功,则说明配置成功了。
下面修改文件.gitlab-ci.yml
,增加一个Release操作:
1 | # .gitlab-ci.yml |
$CI_COMMIT_TAG
是Gitlab定义的环境变量,是版本的标签,可以通过Git工具提交代码时添加新的Tag。
其他Docker尝试
Docker GPU
(Docker GPU)[https://blog.opskumu.com/docker-gpu.html]
Docker Gitlab
(Docker Gitlab)[https://www.jianshu.com/p/080a962c35b6]
安装Gitlab:
1 | # 拉取镜像 |
配置Gitlab文件./gitlab/config/gitlab.rb
:
1 | # 配置http协议所使用的访问地址 |
配置完成后,重启Gitlab:
1 | docker restart gitlab |
Docker DNS
拉取镜像
1 | docker pull dns-server |
其他机器启动时可以使用参数--dns
指定DNS容器。
1 | docker run --dns=xx.xx.xx.xx images |
Docker Machine
在安装Docker Toolbox时,也自动安装了docker machine。利用docker machine可以创建虚拟机(借助VirtualBox),这个虚拟机小巧且精简,附带Docker,但是功能有限。用户如果想要更全功能的Linux虚拟机,可以使用后面的Vagrant。
创建虚拟机
创建虚拟机:
1 | docker-machine create name |
常用命令
1 | docker-machine ls # 列出所有虚拟机 |
切换Docker服务端
默认情况下,我们在开机后初次运行Docker Quickstart Terminal时,它就会为我们启动一个虚拟机,这个虚拟机包含了一个Docker Server,所以 这里不必切换Docker服务端 。
利用Docker Machine可以实现切换Docker Server。如果不想把自己本地的计算机搞乱,我们可以直接安装Docker Client,而服务端通过其他方式创建,也可以正常使用。
切换本地Docker服务端
首先利用上面的docker-machine命令创建带docker server的虚拟机,然后执行下面的操作。
1 | # 使用命令查看虚拟机的环境变量 |
切换阿里云Docker服务端
使用阿里云的ECS,首先得保证账号内有钱。其他云平台道理相同。
进入官方参考页面,点击第三方驱动插件(3rd-party driver plugins),就可以找到Aliyun ECS(点击进入)。
首先是下载驱动,解压文件,修改得到的文件的后缀为.exe
,并将驱动的所在目录添加到环境变量。
打开阿里云平台,管理控制台,访问控制,用户管理,创建AccessKey和Secret。 注意 :Secret只显示一次,一定要保存好。
回到本地命令行,执行:
1 | docker-machine create -d aliyunecs --aliyunecs-io-optimized=optimized --aliyunecs-instance-type=ecs.c5.large --aliyunecs-access-key-id=用户ID --aliyunecs-access-key-secret=用户Secret --aliyunecs-region=cn-qingdao 虚拟机name |
创建好以后,就可以按照上一节的内容切换服务端了。
Vagrant(可选)
Vagrant是一个虚拟机管理工具。可以用脚本的方式快速创建虚拟机(需要安装VirtualBox)以及虚拟机集群。如果不想直接在自己的电脑上安装Docker,可以尝试Vagrant。
Vagrant官网
Vagrant下载页
VirtualBox官网
Vagrant 镜像
官方镜像
首先进入Vagrant官网
,点击Find Boxes
,输入要查找的虚拟机。例如输入Unbutu 16.04
,搜索后进入,选择New,会出现如下页面:
1 | # 创建Vagrantfile |
执行页面中提示的操作,Vagrant会在当前目录创建该虚拟机。
非官方镜像
如果上面的过程太漫长,可以自定义添加Box。打开vagrantbox.es,按照上面的提升操作添加虚拟机镜像。
例如:
1 | vagrant box add ubuntu_new https://atlas.hashicorp.com/envimation/boxes/ubuntu-xenial-docker |
如果命令行下载速度较慢,可以使用迅雷等工具下载到本地,再使用:
1 | vagrant box add ubuntu_new /path/to/box |
也可以到清华镜像下载,选择目录中64位vagrant.box
文件即可。
清华镜像源
Ubuntu 各个版本编号
版本号 | 代号 |
---|---|
16.04 | Xenial |
18.04 | Bionic |
19.04 | Disco |
20.04 | Focal |
Vagrant SSH
在虚拟机目录下执行:
1 | vagrant ssh |
即可进入虚拟机。
Vagrant 常用命令
1 | vagrant box add # 添加一个box |
Vagrant 配置文件
通过编辑脚本也可以利用vagrant同时创建多台虚拟机。
我们在使用之前的方法创建虚拟机时,目录下会自动生成Vagrantfile
文件,这就是Vagrant虚拟机的配置文件,里面包含虚拟机的配置,SSH的配置以及Vagrant的基础配置,这些配置是基于Ruby语法的。
单机模式配置:
1 | # box |
参考脚本配置:
1 | # 例 1: |
配置一个带Docker的Vagrant虚拟机
创建一个目录,并配置如下文件:
- VirtualBox
- labs
- sources.list
- setup.sh
- labs
编辑setup.sh如下:
1 | sudo cp /etc/apt/sources.list /etc/apt/sources.list.back |
编辑sources.list内容如下(适用于ubuntu 16.04,其他版本可以自行搜索):
1 | deb http://mirrors.aliyun.com/ubuntu/ xenial main |
在VirtualBox下执行
1 | vagrant init |
会生成Vagrantfile文件。打卡文件,编辑:
1 | # -*- mode: ruby -*- |
保存后:
1 | vagrant up |
即可创建虚拟机。输入如下命令登录虚拟机:
1 | vagrant ssh |
安装扩展
1 | # 查看插件列表 |
参考文档
Dockerfile 语法
命令
FROM
定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。
1 | FROM scratch # 制作base image |
LABEL
相当于注释:
1 | LABEL maintainer="author@web.com" |
RUN
用于执行后面跟着的命令行命令。
1 | FROM nginx |
另外,Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:
1 | FROM centos |
编辑保存之后就可以构建Docker镜像了。
1 | docker build -t nginx:test . |
CMD
类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
- CMD 在docker run 时运行。
- RUN 是在 docker build用的。
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效;如果在docker run中指明了命令,CMD就会被忽略。
1 | # Shell 格式 |
ENTRYPOINT
ENTRYPOINT会让容器以应用程序或服务的方式运行。它类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
但是, 如果运行 docker run 时使用了 –entrypoint 选项,此选项的参数可当作要运行的程序覆盖 ENTRYPOINT 指令指定的程序。
优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。
注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
1 | ENTRYPOINT ["<executeable>","<param1>","<param2>",...] |
可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。
示例:
假设已通过 Dockerfile 构建了 nginx:test 镜像:
1 | FROM nginx |
1 | # 1、不传参运行 |
WORKDIR
指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。
docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。
1 | WORKDIR <工作目录路径> |
COPY
复制指令,从上下文目录中复制文件或者目录到容器里指定路径。
1 | COPY [--chown=<user>:<group>] <源路径1>... <目标路径> |
ADD
ADD 指令和 COPY 的使用格式一致(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:
- ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
- ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
1 | WORKDIR /root |
如果想要添加远程文件,还是要用命令的方式(curl、wget)较好:
ENV
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
1 | ENV <key> <value> |
ARG
构建参数,与 ENV 作用一至。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
构建命令 docker build 中可以用 –build-arg <参数名>=<值> 来覆盖。
1 | ARG <参数名>[=<默认值>] |
VOLUME
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷,可以通过 -v 参数修改挂载点。
作用:
- 避免重要的数据,因容器重启而丢失,这是非常致命的。
- 避免容器不断变大。
1 | VOLUME ["<路径1>", "<路径2>"...] |
EXPOSE
仅仅只是声明端口。
作用:
- 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
- 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
1 | EXPOSE <端口1> [<端口2>...] |
USER
用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
1 | USER <用户名>[:<用户组>] |
HEALTHCHECK
用于指定某个程序或者指令来监控 docker 容器服务的运行状态。
1 | HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令 |
ONBUILD
用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这是执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。
1 | ONBUILD <其它指令> |
总结
- 应使用LABEL注明文件作用以及内容;
- 应使用ENV注明主要变量,方便维护;
- 应当使用WORKDIR注明工作路径,且推荐使用绝对路径;
- 应使用COPY为主,需要解压时可以使用ADD;
- 应当在使用RUN时,尽量合并命令,防止产生多个层;
- 应当在使用Exec格式时使用”/bin/bash -c”来识别ENV变量,且被执行的指令应放到一起;
YAML 语法
YAML脚本的后缀为yml或yaml,基本语法如下:
- 大小写敏感;
- 使用缩进表示层级关系;
- 缩进不允许使用tab,只允许空格;
- 缩进的空格数不重要,只要相同层级的元素左对齐即可;
- ‘#’表示注释。
YMAL 支持三种数据类型:
- 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
- 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
- 纯量(scalars):单个的、不可再分的值
YAML 对象
对象键值对使用冒号结构表示 key: value,冒号后面要加一个空格。
也可以使用 key:{key1: value1, key2: value2, …}。
还可以使用缩进表示层级关系;
1 | key: |
较为复杂的对象格式,可以使用问号加一个空格代表一个复杂的key,配合一个冒号加一个空格代表一个value,意思即对象的属性是一个数组[complexkey1,complexkey2],对应的值也是一个数组[complexvalue1,complexvalue2]:
1 | ? |
YAML 数组
以 -
开头的行表示构成一个数组:
1 | # 多行表示 |
复合结构
数组和对象可以构成复合结构,例:
1 | languages: |
纯量
- 字符串
- 布尔值
- 整数
- 浮点数
- Null
- 时间
- 日期
表示方法如下
1 | boolean: |
引用
& 用来建立锚点,<< 表示合并到当前数据,* 用来引用锚点:
1 | defaults: |