从docker到k8s
查看linux版本
uname -r
因为Docker 必须在CentOs 7上,要求系统为64位、系统内核版本为3.10以上
Docker运行在CentOs-6.5或更高的版本的CentOS上,要求系统为64位、系统内核版本为2.6.32-431或者更高版本.
所以使用安装之前要查看一下自己linux的CentOs版本是多少
cat /etc/redhat-release
再看内核
uname -r
镜像/容器
用java代码的理解就是 person p1=new person(); person p2=new person(); person p3=new person(); person(模板,类)就是镜像 p1,p2,p3(实例)就是容器
Docker镜像(image)就是一个只读的模板.镜像可以用来创建Docker容器,一个镜像可以创建很多容器.
镜像与容器的关系类似于面向对象编程中的对象与类
镜像就是类 容器就是一个一个的实例对象
Docker利用容器(Container)独立运行的一个或一组应用.容器是用镜像创建的运行实例.
他可以被启动、开始、停止、删除.每个容器都是相互隔离的、保证安全的平台.
可以把容器看做是一个简易版的Linux环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序.容器的定义和镜像几乎一模一样,也是一对的统一视角,唯一区别在于容器的最上面那是一层可读可写的.
仓库(repository)是集中存放镜像文件得场所.
仓库(repository)和仓库注册服务器(registry)是有区别的.
仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,
每个镜像有不同的标签(tag).
仓库分为公开仓库(public)和私有仓库(private)两种形式.
最大的公开仓库是Docker Hub(https://hub.docker.com/),
存放了数据庞大的镜像供用户下载.国内的公开仓库包括阿里云、
网易云等.
需要正确的理解仓储/镜像/容器这几个概念:
Docker本身是一个容器运行载体或称之为管理引擎.
我们把应用程序和配置依赖打包好行成一个可交付的运行环境,
这个打包好的运行环境就似乎image镜像文件.
只有通过这个镜像文件才能生成Docker容器.image文件可以
看作是容器的模板.Docker根据image文件生成容器的实例.
同一个image文件,可以生成多个同时运行的容器实例.
image文件生成的容器实例,本身也是一个文件,称为镜像文件.
一个容器运行一种服务,当我们需要的时候,就可以通过Docker客户端创建一个对应的
运行实例,也就是我们的容器.
至于仓储,就是放了一堆镜像的地方,我们可以把镜像发布到仓储中,
需要的时候从仓储中拉下来就可以了.
----安装步骤
CentOS6.8安装Docker
1.yum install -y epel-release
(Docker使用EPEL发布,RHEL系列的OS首先要确保已经持有EPEL仓库,否则先检查OS的版本,然后安装相应的EPEL包.)
2.yum install -y docker-io(正式安装)
3.安装后的配置文件: /etc/sysconfig/docker
4.启动docker后台服务: service docker start
5.docker version
验证版本
CentOS7安装Docker 安装手册。https://docs.docker.com/install/linux/docker-ce/centos
1.确定你是CentOS7及以上版本 cat /etc/redhat-release
2.yum安装gcc相关 ①CentOS 7 可以连接外网②yum -y install gcc 三 yum -y install gcc-c++
3.卸载旧版本
$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
4.安装需要的软件包
5.设置stable镜像仓库
1、$ sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
2、(这是官网推荐的第二步的安装方式,但是不推荐因为是从docker国外网站下载,经常跑不通,推荐从阿里云)
$ sudo yum-config-manager
–add-repo
https://download.docker.com/linux/centos/docker-ce.repo
$ sudo yum-config-manager
–add-repo
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
Optional:可选的 在官网有两条命令是可选命令可以不执行,使用上关系不大
6.更新yum软件包索引yum makecache fast
7.安装DOCKER CE
yum -y install docker-ce
8.启动
docker systemctl start docker
9.测试
docker version
docker run hello-world
10.配置镜像加速
1.mkdir -p /etc/docker
2.vim /etc/docker/daemon.json
(#网易云{"registry-mirrors":["http://hub-mirror.c.163.com"]})
(#阿里云{"registry-mirrors":["http://.mirror.aliyuncs.com"]})
3.systemctl daemon-reload
4.systemctl restart docker
ps -ef|grep -v grep
11.卸载 systemctl stop docker
yum -y remove docker-ce
rm -rf /var/lib/docker
是什么 https://dev.aliyun.com/search.html
注册一个属于自己的阿里云账号(可复用淘宝账号)
阿里云加速 获得加速器地址连接 1.登录阿里云开发者平台 2.获取加速地址(自己有自己相应的)
配置本机Docker运行镜像加速器
重新启动Docker后台服务:service docker restart
Linux系统下配置完加速器需要检查是否生效
鉴于国内网络问题,后续拉取docker镜像十分缓慢,我们可以需要配置加速器来解决,
我使用的是阿里云的本人自己的账号的镜像地址(需要自己注册一个属于你自己的): https://xxxx.mirror.aliyuncs.com
vim /etc/sysconfig/docker
将获取的自己的账户下的阿里云加速地址配置进去
(配置文件要写的内容)
other args="–registry-mirror=https://XXX.mirror.aliyuncs.com"(CentOS6.x)
DOCKER_CERT_PATH=/etc/docker
DOCKER_NOWARN_KERNEL_VERSION=1
centos 7.0++
1.vim /etc/docker/daemon.json
2.粘进去
{
"registry-mirrors": ["https://22vai9tm.mirror.aliyuncs.com"]
}
3.sudo systemctl daemon-reload
4.sudo systemctl restart docker
这个内容阿里云上都有
```整段粘进去也行
网易云加速器
就是把阿里云的地址换成网易云的地址就可以(推荐使用阿里云)
原理
Docker是一个Client-Server(CS)结构的系统,Docker守护进程运行在主机上,然后通过Socket连接从客户端访问,守护进程从客户端
接受命令并管理运行在主机上的容器.容器,是一个运行时环境,就是我们前面说到的集装箱.
为什么Docker比虚拟机快
(1)docker有着比虚拟机更少的抽象层,更少的硬件,比如打印机等.由于docker不需要Hypervison实现硬件资源虚拟化,运行在
docker容器上的程序直接使用的都是实际物理机的硬件资源.因此在cpu、内存利用率上docker将会在效率上有明显优势.
(2)docker利用的是宿主机的内核,而不是Guest OS.因此,当新建一个容器时,docker不需要和虚拟机和虚拟机一样重新加载
一个操作系统内核.仍热避免引寻、加载操作系统内核返个比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载Guest
OS,返个新建过程是分钟级别.而docker由于直接利用宿主机的操作系统,则省略了返个过程,因此新建一个docker容器只需要几秒钟.
docker常用命令 启动 systemctl start docker
帮助命令:
1、docker version
2、docker info
3、docker --help(重点)
镜像命令
1、docker images(列出本地主机上的镜像)
OPTIONS说明: -a:列出本地所有的镜像(含中间镜像层)
-q:只显示镜像ID
--digests:显示镜像的摘要信息
--no-trunc:显示完整的镜像信息
REPOSITORY:表示镜像的仓库源
TAG:镜像的标签
IMAGE ID:镜像ID
CREATED:镜像创建时间
SIZE:镜像大小
同一个仓库源可以有多个TAG,代表这个仓库源的不同个版本,我们使用REPOSITORY:TAG 来定义不同的镜像.
如果你不指定一个镜像的版本标签,例如你只使用ubuntu,docker将默认使用ubuntu:latest镜像
镜像命令:
docker images
docker search 某个XXX镜像名字 ①网站 https://hub.docker.com docker search [OPTIONS]镜像名字
OPTIONS说明: --no-trunc:显示完整的镜像描述
-s:列出收藏数不小于指定值的镜像.
--automated:只列出 automated build类型的镜像.
docker pull 某个XXX镜像名字
docker rmi 某个XXX镜像名字ID
例如: docker rmi -f hello-world nginx 1、删除镜像
2、删除单个 docker rmi -f 镜像ID
3、删除多个 docker rmi -f 镜像名1:TAG 镜像名2:TAG
4、删除全部 docker rmi -f $(docker images -qa) 相当于组合命令
容器命令:
有镜像才能创建容器,这是根本前提(例如:CentOS演示) ---> docker pull centos
新建并启动容器 ---> docker run[OPTIONS]IMAGE[COMMAND][ARG...] OPTIONS说明(常用):有些是一个减号,有些是两个减号
--name="容器新名字":为容器的一个名称
-d:后台运行容器,并返回容器id,也即启动守护式容器;
-i:以交互模式运行容器,通常与-t同时使用;
-t:为容器重新分配一个伪输入终端,通常与-i同时使用;
-P:随机端口映射;
-p:指定端口映射,有以下四种格式:
ip:hostPort:containerPort
ip::containerPort
hostPort:containerPort
启动交互模式容器: containerPort
---> docker run -it xxxxxx(id)
1---> docker images
2---> docker run -it centos /bin/bash #使用镜像centos:latest以交互模式启动一个容器,在容器内执行/bin/bash 命令
docker images
docker run -it xxxx(id)
列出当前所有正在运行的容器 ---> docker ps [OPTIONS]:
1、-a:列出当前所有正在运行的容器+历史上运行过的
2、-l:显示最近创建的容器/
3、-n:显示最近n个创建的容器
4、-q:静默模式.只显示容器编号
5、--no-trunc:不截断输出
退出容器: 两种退出方式 exit 容器停止退出
ctrl+p+Q 容器不停止退出
创建容器: docker create 镜像id
启动容器: docker start 容器ID或者容器名
重启容器: docker restart 容器ID或者容器名
停止容器: docker stop 容器ID或者容器名
强制停止容器: docker kill 容器ID或者容器名
删除已停止的容器: 1、docker rm 容器ID(已停止容器)
2、docker rm -f 容器ID
一次性删除多个容器: 1、docker rm -f(docker ps -a -q)
2、docker ps -a -q | xargs docker rm
重要:
1、启动守护式容器 -- docker run -d 容器名 说明: 使用镜像centos:last 以 后台模式启动一个容器
docker run -d centos
问题:然后docker ps -a
进行查看,会发现容器已经退出
很重要的要说明一点:Docker容器后台运行,就必须有一个
前台进程.容器运行的命令如果不是那些一直挂起的命令
比如说运行top,tail,就会自动退出的.
这个是docker的机制问题,比如你的web容器,我们以nginx为例,正常情况下,
我们配置启动服务只需要启动相应的service即可.例如:service nginx start
但是,这样做,nginx为后台进程模式运行,就导致docker前台没有运行的应用.
这样的容器后台启动后,会立即自杀因为他觉得他没事可做了.
所以,最佳的解决方案是,将你要运行的程序以前台进程的形式运行.
交互的用 -it 不交互 -d
以后台方式启动但是不关闭的解决方案: docker run -d centos /bin/sh -c "while true;do echo hello zzyy;sleep 2;done"
然后可以查看日志 docker logs 容器id 可以看到他一直在打印 hello zzyy
2、查看容器日志 docker logs -f -t --tail 容器 ID 说明: -t 是加入时间戳 -f 跟随最新的日志打印(就是持续看日志) --tail 数字显示最后多少条
3、查看容器内运行的进程 docker top 容器id
4、查看容器内部细节 docker inspect 容器id
5、进入正在运行的容器并以命令行交互 docker exec -it 容器ID bashShell
重新进入docker attach 容器ID或者容器名
上述两个区别: attach 直接进入容器启动命令的终端,不会启动新的进程
exec 是在容器中打开新的终端,并且可以启动新的进程,相当于隔山打牛,进容器,执行命令后拿到结果,返回宿主机,打印
例如:docker exec -it xxx(容器id) ls -l /tmp 相当于进入容器 执行 ls -l 命令 然后回到宿主机 ,打印结果
6、从容器内拷贝文件到主机上 docker cp 容器id:容器内路径 目的主机路径 例如: docker cp 容器id:/tmp/yum.log /root
Docker 镜像:
是什么? 镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境
开发的软件,它包含运行某个软件所需的所有内容
UnionFS(联合文件系统) :
UnionFS(联合文件系统) : Union文件系统是一种分层、轻量级并且高性能的文件想系统,它支持对文件系统的修改作为
一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unit several directories into a single virtual filesystem).
Union 文件系统是Docker镜像的基础.镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像.
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的
Docker镜像加载原则:
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS.
bootfs(boot file system)主要包含bootloader和kernel,bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层
是bootfs.这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核.当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs
转交内核,此时系统也会卸载bootfs.
rootfs(root file system),在bootfs之上,包含的就是典型Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件.rootfs就是各种不同的操作系统发行版,
比如Ubuntu,Centos等等.
分层的镜像
为什么Docker镜像要采用这种分层结构呢 : 最大的一个好处就是--共享资源 比如:有多个镜像都从相同的base镜像构建而来,那么宿主机只需要在磁盘上保存一份base镜像,同时
内存中也只需加载一份base镜像,就可以为所有容器服务了,而且镜像的每一层都可以被共享.
特点 : Docker镜像都是只读的
当容器启动时,一个新的可写层被加载到镜像的顶部.这一层
通常被称为"容器层","容器层"之下的都叫镜像层.
Docker镜像commit操作补充: docker commit 提交容器副本使之成为一个新的镜像
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
案例演示: 1、从Hub上下载tomcat镜像到本地并成功运行 docker run -it -p 8080:8080 tomcat -p 主机端口:docker容器端口 -P:随机分配端口 i:交互 t:终端
2、故意删除上一步镜像生产tomcat容器的文档
3、也即当前的tomcat运行实例是一个没有文档内容的容器,以他为模板commit一个没有doc的tomcat新镜像atguigu/tomcat02
docker commit -a="zzyy" -m="del tomcat docs" 容器id 容器名(atchy/tomcat02:1.2)
4、启动我们的新镜像并和原来的对比
Docker 容器数据卷 是什么:
卷就是目录或文件,存在于一个或多个容器中,都docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供
一些用于持续存储或共享数据的特点:
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时
删除共挂载的数据卷
特点:
1、数据卷可在容器之间共享或重用数据
2、卷中的更改可以直接生成
3、数据卷中的更改不会包含在镜像的更新中
4、数据卷的生命周期一直持续到没有容器使用它为止
能干嘛:
容器持久化
容器间继承+共享数据
数据卷: 容器内添加 直接命令添加 命令 docker run -it -v /宿主机绝对路径目录:/容器内目录 镜像名
docker run -it -v /myDataVolume:/dataVolumeContainer centos
容器停止退出后,主机修改后数据是否同步 同步
docker run -it -v /myDataVolume:/dataVolumeContainer centos
带权限docker run -it -v /myDataVolume:/dataVolumeContainer:ro centos
命令 docker run -it 镜像名
docker run -it -v /myDataVolume:/dataVolumeContainer 镜像名
docker run -it -v /myDataVolume:/dataVolumeContainer:ro 镜像名 (ro : 只读 readonly)
DockerFile添加:
说明:Hello.java ---> Hell0.class
Docker images ===> DockerFile
类似于镜像的描述文件
步骤:1、根目录下新建mydocker文件夹并进入
2、可在Dockerfile中使用VOLUME指令来给镜像添加一个或多个数据卷
什么是VOLUME指令 :
VOLUMEN["/dataVolumeContainer","/dataVolumeContainer2","/dataVolumeContainer3"]
# volume test
# FROM centos 相当于 extends
FROM centos
#在根目录下新建两个容器卷iujk
VOLUME ["/dataVolumeContainer1","/dataVolumeContainer2"]
#打印日志
CMD echo "finished,---------success1"
# 相当于 docker run -it -v /host:/dataVolumeContainer1 -v /host:/dataVolumeContainer2 centos /bin/bash
CMD /bin/bash
说明:
出于可移植和分享的考虑,用-v主机目录:容器目录这种方法不能够直接在Dockerfile中实现.由于宿主机目录是依赖于特定宿主机的,并不能够保证在所有的宿主机上都存在这样的特定目录.
3、File构建
4、build后生成镜像 docker build -f /mydocker/dockerfile -t zzyy/centos . (注意有个点) 就可以通过docker images 查看获得的新的镜像
5、run容器
6、通过上述步骤,容器内的卷目录地址一经知道对应的主机目录地址在哪??
主机对应默认地址
备注:Docker挂载主机目录Docker访问出现cannot open directory .:Permission denied 解决方法:在挂载目录后多加一个--privileged=true即可
docker run -it -v /myDataVolume:/dataVolumeContainer --privileged=true 镜像名
数据卷容器
DockerFile解析 是什么: 1、DockerFile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本.
2、构建三步骤 编写Dockerfile文件 docker build docker run
3、文件什么样? 以我们熟悉的CentOS为例
DockerFile构建过程解析 Dockerfile内容基础知识: 1、每天保留字指令都必须为大写字母且后面要跟随至少一个参数
2、指令按照从上到下,顺序执行
3、#表示注释
4、每条指令都会创建一个新的镜像层,并对镜像进行 提交
Docker执行Dockerfile的大致流程: (1)docker从基础镜像运行一个容器
(2)执行一条指令并对容器作出修改
(3)执行类似docker commit的操作提交一个新的镜像层
(4)docker再基于刚提交的镜像运行一个新容器
(5)执行dockerfile中的下一条指令直到所有指令都执行完成
小总结: 从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器跟别代表软件的三个不同阶段,
·Dockerfile是软件的原材料
·Docker镜像是软件的交付品
·Docker容器则可以认为是软件的运行态.
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石.\
1、Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西.Dockerfile涉及的内容包括执行代码或者是
文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和
内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
2、Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行Docker镜像时,会真正开始提供
服务;
3、Docker容器,容器是直接提供服务的.
DockerFile体系构建(保留字指令):
FROM:基础镜像,当前编写的镜像是基于哪个镜像
MAINTAINER:镜像维护者的姓名和邮箱地址
RUN:容器构建时需要运行的命令
EXPOSE:当前容器对外暴露的端口
WORKDIR:指定在创建容器后,终端默认登录的进来的工作目录,一个落脚点
ENV:用来在构建镜像过程中设置环境变量 例如: ENV MY_PATH /usr/mytest
这个环境变量可以在后续的任何
RUN指令中使用,这就如同在命令前面
指定了环境变量前缀一样;也可以在其他
指令中直接使用这个环境变量, 比如:WORKDIR $MY_PATH
ADD:将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包
COPY:类似ADD,拷贝文件和目录到镜像中,将从构建上下文目录中<源路径>的文件/目录复制到新的一层镜像内的<目标路径>位置 COPY src dest 或者 COPY["src","dest"]
VOLUME:容器数据卷,用于数据保存和持久化工作
CMD:指定一个容器启动时要运行的一个命令 CMD容器启动命令:
Dockerfile中可以有多个CMD指令,但只有最后一个生效
,CMD会被docker run之后的参数替换 CMD 指令的格式和 RUN相似,也是两种格式:
shell格式:CMD<命令>
exec格式:CMD["可执行文件","参数1","参数2"...]
参数列表的格式:CMD["参数1","参数2"...],在指定了ENTRYPOINT指令后,用CMD指令具体的参数.
ENTRYPOINT:指定一个容器启动时要运行的一个命令
ENTRYPOINT的目的和CMD一样,都是在指定容器启动程序及参数
ONBUILD:(触发器)当构建一个被继承的Dockerfile时运行命令,父镜像在被子继承后父镜像的onbuild被触发
小总结
案例: Base镜像(scratch) Docker Hub中99%的镜像都是通过在base镜像中安装和配置需要的软件构建出来的
案例 Base镜像(scratch) Docker Hub 的镜像都是通过base镜像中安装和配置需要的
软件构建出来的
自定义镜像mycentos 1、编写 (1)Hub默认CentOS镜像什么情况
(2)准备编写DockerFile文件
(3)myCentOS内容DockerFile
2、构建 docker build -f /dockerFiles/dockerFile -t mycentos:1.3 .
3、运行 docker run -it 新镜像名字:TAG
4、列出镜像的变更历史 docker history
CMD/ENTRYPOINT 镜像案例 都是指定一个容器启动时要运行的命令
CMD:Dockerfile中可以有多个CMD指令,但只有最后一个生效,CMD会被docker run之后的参数替换
Case--tomcat的讲解演示
ENTRYPOINT:docker run之后的参数会被当做参数传递给ENTRYPOINT,之后形成新的命令组合
案例:制作CMD版可以查询IP信息的容器
问题
WHY
制作ENTRYPOINT 版本询IP信息的容器
curl命令可以用来执行下载、发送各种HTTP请求,指定HTTP头部等操作,
如果系统没有curl可以使用yum install curl安装,也可以下载安装.
curl是将下载文件输出到stdout
使用命令:curl http://www.baidu.com
执行后,html就会显示在屏幕上
这是最简单的使用方法,用这个命令获得了页面,如果这里的URL只想的是一个文件
或者一幅图都可以直接下载到本地,如果下载的事HTML文档,那么缺省的将只显示文件
头部,即HTML文档的header.要全部显示,请假参数-i
小总结
docker run -d -p 9080:8080 --name myt9
-v /zzyyuser/mydockerfile/tomcat9/test:/usr/local/apache-tomcat-9.0.8/webapps/test
-v /zzyyuser/mydockerfile/tomcat9/tomcat9logs:/usr/local/apache-tomcat-9.0.8/logs
--privileged=true
zzyytomcat9
Docker常用安装 总体步骤: 搜索镜像 拉取镜像 查看镜像 启动镜像 停止容器 移除容器
安装mysql: docker hub上面查找mysql镜像
docker hub上(阿里云加速器)拉取mysql镜像到本地标签为5.6
使用mysql5.6镜像创建容器(也叫运行镜像)
docker run -p 12345:3306 --name mysql -v /zzyyuse/mysql/conf:/etc/mysql/conf.d -v /zzyyuse/mysql/logs:/logs -v /zzyyuse/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.6
命令说明: -p 12345:3306: 将主机的12345端口映射到docker容器的3306端口.
--name mysql: 运行服务名字
-v /zzyyuse/mysql/conf:/etc/mysql/conf.d : 将主机/zzyyuse/mysql目录下的conf/my.cnf 挂载到容器的 /etc/mysql/conf.daemon-reload
-v /zzyyuse/mysql/logs:/logs: 将主机/zzyyuse/mysql目录下的logs目录挂载到容器的/logs
-v /zzyyuse/mysql/data:/var/lib/mysql: 将主机/zzyyuse/mysql目录下的data目录挂载到容器的/var/lib/mysql
-e MYSQL_ROOT_PASSWORD=123456: 初始化root用户的密码
-d mysql:5.6 : 后台程序运行mysql5.6
安装redis:docker run -p 6379:6379
-v /home/chysoftware/myredis/data:/data
-v /home/chysoftware/myredis/conf/redis.conf:/usr/local/etc/redis/redis.conf
-d redis:3.2 redis-server /usr/local/etc/redis/redis.conf
--appendonly yes
本地镜像发布到阿里云: 本地镜像发布到阿里云流程
镜像的生成方法: 1.前面的Dockerfile
2.从容器创建一个新的镜像
docker commit [OPTIONS] 容器id [REPOSITORY[:TAG]] 说明: -a:提交镜像作者;
-m:提交时的说明文字;
docker commit -a chy -m "new mycentos 1.4 from 1.3" 容器id mycentos:1.4
将本地镜像推送到阿里云: 1、本地镜像素材原型
2、阿里云开发者平台 ==> https://dev.aliyun.com/search.html
3、创建仓库镜像 命名空间 仓库名称
4、将镜像推送到registry
$ sudo docker login --username=chy521aly registry.cn-beijing.aliyuncs.com
$ sudo docker tag [ImageId] registry.cn-beijing.aliyuncs.com/chyalydocker/alyrepository:[镜像版本号]
$ sudo docker push registry.cn-beijing.aliyuncs.com/chyalydocker/alyrepository:[镜像版本号]
5、公有云可以查询到
6、查看详情
将阿里云上的镜像下载到本地
Kubernetes
是一个集群
上面有
master(主节点)/node(工作节点)
·主节点master之上有三个组件(三个守护进程): API Server 、 Scheduler 、 Controller-Manager
·node: kubelet,docker…
Pod,Label,Label Selector
API Server简介
k8s API Server提供了k8s各类资源对象(pod,RC,Service等)的增删改查及watch等HTTP Rest接口,是整个系统的数据总线和数据中心。
kubernetes API Server的功能:
提供了集群管理的REST API接口(包括认证授权、数据校验以及集群状态变更);
提供其他模块之间的数据交互和通信的枢纽(其他模块通过API Server查询或修改数据,只有API Server才直接操作etcd);
是资源配额控制的入口;
拥有完备的集群安全机制.
kube-apiserver工作原理图
如何访问kubernetes API
k8s通过kube-apiserver这个进程提供服务,该进程运行在单个k8s-master节点上。默认有两个端口。
k8s通过kube-apiserver这个进程提供服务,该进程运行在单个k8s-master节点上。默认有两个端口。
-
本地端口
该端口用于接收HTTP请求;
该端口默认值为8080,可以通过API Server的启动参数“–insecure-port”的值来修改默认值;
默认的IP地址为“localhost”,可以通过启动参数“–insecure-bind-address”的值来修改该IP地址;
非认证或授权的HTTP请求通过该端口访问API Server。
2.安全端口
该端口默认值为6443,可通过启动参数“--secure-port”的值来修改默认值;
默认IP地址为非本地(Non-Localhost)网络端口,通过启动参数“--bind-address”设置该值;
该端口用于接收HTTPS请求;
用于基于Tocken文件或客户端证书及HTTP Base的认证;
用于基于策略的授权;
默认不启动HTTPS安全访问控制。
kubernetes API访问方式
Kubernetes REST API可参考https://kubernetes.io/docs/api-reference/v1.6/
- curl
curl localhost:8080/api
curl localhost:8080/api/v1/pods
curl localhost:8080/api/v1/services
curl localhost:8080/api/v1/replicationcontrollers
2. Kubectl Proxy
Kubectl Proxy代理程序既能作为API Server的反向代理,也能作为普通客户端访问API Server的代理。通过master节点的8080端口来启动该代理程序。
kubectl proxy --port=8080 &
具体见kubectl proxy --help
3. kubectl客户端
命令行工具kubectl客户端,通过命令行参数转换为对API Server的REST API调用,并将调用结果输出。
命令格式:kubectl [command] [options]
具体可参考Kubernetes常用命令
4. 编程方式调用
使用场景:
1、运行在Pod里的用户进程调用kubernetes API,通常用来实现分布式集群搭建的目标。
2、开发基于kubernetes的管理平台,比如调用kubernetes API来完成Pod、Service、RC等资源对象的图形化创建和管理界面。可以使用kubernetes提供的Client Library。
具体可参考https://github.com/kubernetes/client-go。
通过API Server访问Node、Pod和Service
k8s API Server最主要的REST接口是资源对象的增删改查,另外还有一类特殊的REST接口—k8s Proxy API接口,这类接口的作用是代理REST请求,即kubernetes API Server把收到的REST请求转发到某个Node上的kubelet守护进程的REST端口上,由该kubelet进程负责响应。
- Node相关接口
关于Node相关的接口的REST路径为:/api/v1/proxy/nodes/{name},其中{name}为节点的名称或IP地址。
/api/v1/proxy/nodes/{name}/pods/ #列出指定节点内所有Pod的信息
/api/v1/proxy/nodes/{name}/stats/ #列出指定节点内物理资源的统计信息
/api/v1/prxoy/nodes/{name}/spec/ #列出指定节点的概要信息
这里获取的Pod信息来自Node而非etcd数据库,两者时间点可能存在偏差。如果在kubelet进程启动时加–enable-debugging-handles=true参数,那么kubernetes Proxy API还会增加以下接口:
/api/v1/proxy/nodes/{name}/run #在节点上运行某个容器
/api/v1/proxy/nodes/{name}/exec #在节点上的某个容器中运行某条命令
/api/v1/proxy/nodes/{name}/attach #在节点上attach某个容器
/api/v1/proxy/nodes/{name}/portForward #实现节点上的Pod端口转发
/api/v1/proxy/nodes/{name}/logs #列出节点的各类日志信息
/api/v1/proxy/nodes/{name}/metrics #列出和该节点相关的Metrics信息
/api/v1/proxy/nodes/{name}/runningpods #列出节点内运行中的Pod信息
/api/v1/proxy/nodes/{name}/debug/pprof #列出节点内当前web服务的状态,包括CPU和内存的使用情况
2. Pod相关接口
/api/v1/proxy/namespaces/{namespace}/pods/{name}/{path:*} #访问pod的某个服务接口
/api/v1/proxy/namespaces/{namespace}/pods/{name} #访问Pod
#以下写法不同,功能一样
/api/v1/namespaces/{namespace}/pods/{name}/proxy/{path:*} #访问pod的某个服务接口
/api/v1/namespaces/{namespace}/pods/{name}/proxy #访问Pod
3. Service相关接口
/api/v1/proxy/namespaces/{namespace}/services/{name}
Pod的proxy接口的作用:在kubernetes集群之外访问某个pod容器的服务(HTTP服务),可以用Proxy API实现,这种场景多用于管理目的,比如逐一排查Service的Pod副本,检查哪些Pod的服务存在异常问题。
集群功能模块之间的通信
kubernetes API Server作为集群的核心,负责集群各功能模块之间的通信,集群内各个功能模块通过API Server将信息存入etcd,当需要获取和操作这些数据时,通过API Server提供的REST接口(GET\LIST\WATCH方法)来实现,从而实现各模块之间的信息交互。
- kubelet与API Server交互
每个Node节点上的kubelet定期就会调用API Server的REST接口报告自身状态,API Server接收这些信息后,将节点状态信息更新到etcd中。kubelet也通过API Server的Watch接口监听Pod信息,从而对Node机器上的POD进行管理。
监听信息
kubelet动作
备注
新的POD副本被调度绑定到本节点 执行POD对应的容器的创建和启动逻辑
POD对象被删除 删除本节点上相应的POD容器
修改POD信息 修改本节点的POD容器
2. kube-controller-manager与API Server交互
kube-controller-manager中的Node Controller模块通过API Server提供的Watch接口,实时监控Node的信息,并做相应处理。
3. kube-scheduler与API Server交互
Scheduler通过API Server的Watch接口监听到新建Pod副本的信息后,它会检索所有符合该Pod要求的Node列表,开始执行Pod调度逻辑。调度成功后将Pod绑定到目标节点上。
API Server参数介绍
API Server 主要是和 etcd 打交道,并且对外提供 HTTP 服务,以及进行安全控制,因此它的命令行提供的参数也主要和这几个方面有关。下面是一些比较重要的参数以及说明(不同版本参数可能会有不同):
参数 含义 默认值
–advertise-address 通过该 ip 地址向集群其他节点公布 api server 的信息,必须能够被其他节点访问 nil
–allow-privileged 是否允许 privileged 容器运行 false
–admission-control 准入控制 AlwaysAdmit
–authorization-mode 授权模式 ,安全接口上的授权 AlwaysAllow
–bind-address HTTPS 安全接口的监听地址 0.0.0.0
–secure-port HTTPS 安全接口的监听端口 6443
–cert-dir TLS 证书的存放目录 /var/run/kubernetes
–etcd-prefix 信息存放在 etcd 中地址的前缀 “/registry”
–etcd-servers 逗号分割的 etcd server 地址 []
–insecure-bind-address HTTP 访问的地址 127.0.0.1
–insecure-port HTTP 访问的端口 8080
–log-dir 日志存放的目录
–service-cluster-ip-range service 要使用的网段,使用 CIDR 格式,参考 kubernetes 中 service 的定义
API Server安装和运行
API Server 是通过提供的 kube-apiserver 二进制文件直接运行的,下面的例子指定了 service 分配的 ip 范围,etcd 的地址,和对外提供服务的 ip 地址:
/usr/bin/kube-apiserver \
--service-cluster-ip-range=10.20.0.1/24 \
--etcd-servers=http://127.0.0.1:2379 \
--advertise-address=192.168.8.100 \
--bind-address=192.168.8.100 \
--insecure-bind-address=192.168.8.100 \
--v=4
直接访问 8080 端口,API Server 会返回它提供了哪些接口:
[[email protected] vagrant]# curl http://192.168.8.100:8080
{
"paths": [
"/api",
"/api/v1",
"/apis",
"/apis/apps",
"/apis/apps/v1alpha1",
"/apis/autoscaling",
"/apis/autoscaling/v1",
"/apis/batch",
"/apis/batch/v1",
"/apis/batch/v2alpha1",
"/apis/extensions",
"/apis/extensions/v1beta1",
"/apis/policy",
"/apis/policy/v1alpha1",
"/apis/rbac.authorization.k8s.io",
"/apis/rbac.authorization.k8s.io/v1alpha1",
"/healthz",
"/healthz/ping",
"/logs/",
"/metrics",
"/swaggerapi/",
"/ui/",
"/version"
]
}
而目前最重要的路径是 /api/v1,里面包含了 kubernetes 所有资源的操作,比如下面的 nodes:
➜ ~ http http://192.168.8.100:8080/api/v1/nodes
HTTP/1.1 200 OK
Content-Length: 112
Content-Type: application/json
Date: Thu, 08 Sep 2016 08:14:45 GMT
{
"apiVersion": "v1",
"items": [],
"kind": "NodeList",
"metadata": {
"resourceVersion": "12",
"selfLink": "/api/v1/nodes"
}
}
API 以 json 的形式返回,会通过 apiVersion 来说明 API 版本号,kind 说明请求的是什么资源。不过这里面的内容是空的,因为目前还没有任何 kubelet 节点接入到我们的 API Server。对应的,pod 也是空的:
➜ ~ http http://192.168.8.100:8080/api/v1/pods
HTTP/1.1 200 OK
Content-Length: 110
Content-Type: application/json
Date: Thu, 08 Sep 2016 08:18:53 GMT
{
"apiVersion": "v1",
"items": [],
"kind": "PodList",
"metadata": {
"resourceVersion": "12",
"selfLink": "/api/v1/pods"
}
}
添加节点
添加节点也非常简单,启动 kubelet 的时候使用 --api-servers 指定要接入的 API Server 就行。kubelet 启动之后,会把自己注册到指定的 API Server,然后监听 API 对应 pod 的变化,根据 API 中 pod 的实际信息来管理节点上 pod 的生命周期。
现在访问 /api/v1/nodes 就能看到已经添加进来的节点:
➜ ~ http http://192.168.8.100:8080/api/v1/nodes
HTTP/1.1 200 OK
Content-Type: application/json
Date: Thu, 08 Sep 2016 08:27:44 GMT
Transfer-Encoding: chunked
{
"apiVersion": "v1",
"items": [
{
"metadata": {
"annotations": {
"volumes.kubernetes.io/controller-managed-attach-detach": "true"
},
"creationTimestamp": "2016-09-08T08:23:01Z",
"labels": {
"beta.kubernetes.io/arch": "amd64",
"beta.kubernetes.io/os": "linux",
"kubernetes.io/hostname": "192.168.8.100"
},
"name": "192.168.8.100",
"resourceVersion": "65",
"selfLink": "/api/v1/nodes/192.168.8.100",
"uid": "74e16eba-759d-11e6-b463-080027c09e5b"
},
"spec": {
"externalID": "192.168.8.100"
},
"status": {
"addresses": [
{
"address": "192.168.8.100",
"type": "LegacyHostIP"
},
{
"address": "192.168.8.100",
"type": "InternalIP"
}
],
"allocatable": {
"alpha.kubernetes.io/nvidia-gpu": "0",
"cpu": "1",
"memory": "502164Ki",
"pods": "110"
},
"capacity": {
"alpha.kubernetes.io/nvidia-gpu": "0",
"cpu": "1",
"memory": "502164Ki",
"pods": "110"
},
"conditions": [
{
"lastHeartbeatTime": "2016-09-08T08:27:36Z",
"lastTransitionTime": "2016-09-08T08:23:01Z",
"message": "kubelet has sufficient disk space available",
"reason": "KubeletHasSufficientDisk",
"status": "False",
"type": "OutOfDisk"
},
{
"lastHeartbeatTime": "2016-09-08T08:27:36Z",
"lastTransitionTime": "2016-09-08T08:23:01Z",
"message": "kubelet has sufficient memory available",
"reason": "KubeletHasSufficientMemory",
"status": "False",
"type": "MemoryPressure"
},
{
"lastHeartbeatTime": "2016-09-08T08:27:36Z",
"lastTransitionTime": "2016-09-08T08:24:56Z",
"message": "kubelet is posting ready status",
"reason": "KubeletReady",
"status": "True",
"type": "Ready"
}
],
"daemonEndpoints": {
"kubeletEndpoint": {
"Port": 10250
}
},
"images": [
{
"names": [
"172.16.1.41:5000/nginx:latest"
],
"sizeBytes": 425626718
},
{
"names": [
"172.16.1.41:5000/hyperkube:v0.18.2"
],
"sizeBytes": 207121551
},
{
"names": [
"172.16.1.41:5000/etcd:v3.0.4"
],
"sizeBytes": 43302056
},
{
"names": [
"172.16.1.41:5000/busybox:latest"
],
"sizeBytes": 1092588
},
{
"names": [
"172.16.1.41:5000/google_containers/pause:0.8.0"
],
"sizeBytes": 241656
}
],
"nodeInfo": {
"architecture": "amd64",
"bootID": "48955926-11dd-4ad3-8bb0-2585b1c9215d",
"containerRuntimeVersion": "docker://1.10.3",
"kernelVersion": "3.10.0-123.13.1.el7.x86_64",
"kubeProxyVersion": "v1.3.1-beta.0.6+fbf3f3e5292fb0",
"kubeletVersion": "v1.3.1-beta.0.6+fbf3f3e5292fb0",
"machineID": "b9597c4ae5f24494833d35e806e00b29",
"operatingSystem": "linux",
"osImage": "CentOS Linux 7 (Core)",
"systemUUID": "823EB67A-057E-4EFF-AE7F-A758140CD2F7"
}
}
}
],
"kind": "NodeList",
"metadata": {
"resourceVersion": "65",
"selfLink": "/api/v1/nodes"
}
}
我们可以看到,kubelet 收集了很多关于自身节点的信息,这些信息也会不断更新。这些信息里面不仅包含节点的系统信息(系统架构,操作系统版本,内核版本等)、还有镜像信息(节点上有哪些已经下载的 docker 镜像)、资源信息(Memory 和 Disk 的总量和可用量)、以及状态信息(是否正常,可以分配 pod等)。
和 API Server 通信
编写的 yaml 文件转换成 json 格式,保存到文件里。主要注意的是,我们指定了 nodeName 的名字,这个名字必须和之前通过 /api/v1/nodes 得到的结果中 metadata.labels.kubernetes.io/hostname 保持一致:
[[email protected] vagrant]# cat nginx_pod.yml
apiVersion: v1
kind: Pod
metadata:
name: nginx-server
spec:
NodeName: 192.168.8.100
containers:
- name: nginx-server
image: 172.16.1.41:5000/nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: /var/log/nginx
name: nginx-logs
- name: log-output
image: 172.16.1.41:5000/busybox
command:
- bin/sh
args: [-c, 'tail -f /logdir/access.log']
volumeMounts:
- mountPath: /logdir
name: nginx-logs
volumes:
- name: nginx-logs
emptyDir: {}
使用 curl 执行 POST 请求,设置头部内容为 application/json,传过去文件中的 json 值,可以看到应答(其中 status 为 pending,表示以及接收到请求,正在准备处理):
# curl -s -X POST -H "Content-Type: application/json" http://192.168.8.100:8080/api/v1/namespaces/default/pods --data @nginx_pod.json
{
"kind": "Pod",
"apiVersion": "v1",
"metadata": {
"name": "nginx-server",
"namespace": "default",
"selfLink": "/api/v1/namespaces/default/pods/nginx-server",
"uid": "888e95d0-75a9-11e6-b463-080027c09e5b",
"resourceVersion": "573",
"creationTimestamp": "2016-09-08T09:49:28Z"
},
"spec": {
"volumes": [
{
"name": "nginx-logs",
"emptyDir": {}
}
],
"containers": [
{
"name": "nginx-server",
"image": "172.16.1.41:5000/nginx",
"ports": [
{
"containerPort": 80,
"protocol": "TCP"
}
],
"resources": {},
"volumeMounts": [
{
"name": "nginx-logs",
"mountPath": "/var/log/nginx"
}
],
"terminationMessagePath": "/dev/termination-log",
"imagePullPolicy": "Always"
}
],
"restartPolicy": "Always",
"terminationGracePeriodSeconds": 30,
"dnsPolicy": "ClusterFirst",
"nodeName": "192.168.8.100",
"securityContext": {}
},
"status": {
"phase": "Pending"
}
}
返回中包含了我们提交 pod 的信息,并且添加了 status、metadata 等额外信息。
等一段时间去查询 pod,就可以看到 pod 的状态已经更新了:
➜ http http://192.168.8.100:8080/api/v1/namespaces/default/pods
HTTP/1.1 200 OK
Content-Type: application/json
Date: Thu, 08 Sep 2016 09:51:29 GMT
Transfer-Encoding: chunked
{
"apiVersion": "v1",
"items": [
{
"metadata": {
"creationTimestamp": "2016-09-08T09:49:28Z",
"name": "nginx-server",
"namespace": "default",
"resourceVersion": "592",
"selfLink": "/api/v1/namespaces/default/pods/nginx-server",
"uid": "888e95d0-75a9-11e6-b463-080027c09e5b"
},
"spec": {
"containers": [
{
"image": "172.16.1.41:5000/nginx",
"imagePullPolicy": "Always",
"name": "nginx-server",
"ports": [
{
"containerPort": 80,
"protocol": "TCP"
}
],
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"volumeMounts": [
{
"mountPath": "/var/log/nginx",
"name": "nginx-logs"
}
]
},
{
"args": [
"-c",
"tail -f /logdir/access.log"
],
"command": [
"bin/sh"
],
"image": "172.16.1.41:5000/busybox",
"imagePullPolicy": "Always",
"name": "log-output",
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"volumeMounts": [
{
"mountPath": "/logdir",
"name": "nginx-logs"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"nodeName": "192.168.8.100",
"restartPolicy": "Always",
"securityContext": {},
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"emptyDir": {},
"name": "nginx-logs"
}
]
},
"status": {
"conditions": [
{
"lastProbeTime": null,
"lastTransitionTime": "2016-09-08T09:49:28Z",
"status": "True",
"type": "Initialized"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2016-09-08T09:49:44Z",
"status": "True",
"type": "Ready"
},
{
"lastProbeTime": null,
"lastTransitionTime": "2016-09-08T09:49:44Z",
"status": "True",
"type": "PodScheduled"
}
],
"containerStatuses": [
{
"containerID": "docker://8b79eeea60f27b6d3f0a19cbd1b3ee3f83709bcf56574a6e1124c69a6376972d",
"image": "172.16.1.41:5000/busybox",
"imageID": "docker://sha256:8c566faa3abdaebc33d40c1b5e566374c975d17754c69370f78c00c162c1e075",
"lastState": {},
"name": "log-output",
"ready": true,
"restartCount": 0,
"state": {
"running": {
"startedAt": "2016-09-08T09:49:43Z"
}
}
},
{
"containerID": "docker://96e64cdba7b05d4e30710a20e958ff5b8f1f359c8d16d32622b36f0df0cb353c",
"image": "172.16.1.41:5000/nginx",
"imageID": "docker://sha256:51d764c1fd358ce81fd0e728436bd0175ff1f3fd85fc5d1a2f9ba3e7dc6bbaf6",
"lastState": {},
"name": "nginx-server",
"ready": true,
"restartCount": 0,
"state": {
"running": {
"startedAt": "2016-09-08T09:49:36Z"
}
}
}
],
"hostIP": "192.168.8.100",
"phase": "Running",
"podIP": "172.17.0.2",
"startTime": "2016-09-08T09:49:28Z"
}
}
],
"kind": "PodList",
"metadata": {
"resourceVersion": "602",
"selfLink": "/api/v1/namespaces/default/pods"
}
}
可以看到 pod 已经在运行,并且给分配了 ip:172.17.0.2,通过 curl 也可以访问它的服务:
[[email protected] vagrant]# curl -s http://172.17.0.2 | head -n 5
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx on Debian!</title>
<style>
kubectl -s http://ip:8080 get pods