最近做边缘计算项目,因为没有基础,所以首先学习Kubernetes。感觉系统的中文入门资料比较少,只找到《Kubernetes权威指南》(龚正、吴治辉等著,下称《指南》),照着第一章的demo教程编写,前前后后遇到不少问题,也是找了好多资料才解决。所以从头写一下如何配置一个单机版MySQL+Tomcat的demo,希望能给陷入同样困境的同学一点帮助。
文章较长,如果你已经按照《指南》的demo走了一遍,但是遇到了问题,可以直接看最后的“坑点总结”中的解决方案能否解决你的问题。
前导知识
本着对零基础的同学友好的态度,前排提示阅读本文前你至少需要以下知识:
也就是说,以上的知识本文不会详细展开。如果其中有读者从来没有听说过的概念,最好先学习一下。
实验环境
笔者的实验环境:
Win10 + VMWare14中安装CentOS 7(带GUI),桥接模式上网
之所以强调是CentOS 7(包括RHEL 7),是因为它的系统服务配置使用的是systemctl命令,这可能与其他CentOS版本或Linux发行版有所不同。当然,如果你对Linux的系统服务配置有经验,可以不采用和笔者相同的版本。
另外,下面所有操作最好在root下进行,避免出现权限不足的问题。
基本上按照《指南》中的环境准备如下:
终端输入以下命令关闭防火墙:
systemctl disable firewalld #禁止防火墙开机启动
systemctl stop firewalld #关闭防火墙服务
如果tab之后有后缀.service是一样的,不带后缀的是简称。
可以使用下面的命令查看防火墙是否已经关闭,如果是inactive表明已关闭:
systemctl status firewalld
当然,生产环境需要自己配置端口访问控制,不能完全关闭防火墙。这里因为是较安全的内网,学习和测试用,直接关闭比较方便。
yum install -y etcd kubernetes
kubernetes的每个组件有各自的配置文件,可以自定义。而该命令会执行默认配置的安装,对kubernetes尚不了解时一键安装非常方便。
如果安装缓慢,可以尝试更换国内的yum安装源,或者代理上网(虚拟机可以共享物理机的代理端口,SSR和clash软件都有允许局域网共享的功能)。
此处需要修改两处配置文件。
Docker配置文件为/etc/sysconfig/docker,将OPTIONS的内容设置为:
OPTIONS='--selinux-enabled=false --insecure-registry gcr.io'
可以注释OPTIONS所在行,而非删除它,以留出容错空间ω。
Kubernetes apiserver配置文件为/etc/kubernetes/apiserver,将--admission_control参数中的ServiceAccount删除(同样地,可以注释原行,复制一行来修改)。也就是更改为:
KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ResourceQuota"
也许你的--admission_control参数并不是在KUBE_ADMISSION_CONTROL变量下,但是在哪里其实是一样的,只要之后的变量读取都有录入即可(不细讲,笔者也尚未完全学习),这里只需要删除。
按顺序启动以下服务:
systemctl start etcd
systemctl start docker
systemctl start kube-apiserver
systemctl start kube-controller-manager
systemctl start kube-scheduler
systemctl start kubelet
systemctl start kube-proxy
至于为什么要按顺序,笔者认为是因为后面的服务对前面的有依赖,启动顺序不对可能会导致某些意外错误。
这里有一个坑点,就是kube-apiserver启动时必须要开启网络连接,否则会报错:
Job for kube-apiserver.service failed because the control process exited with error code. See "systemctl status kube-apiserver.service" and "journalctl -xe" for details.
因为笔者系统是带GUI的,直接在右上角设置网络连接即可。如果是纯字符界面可能需要自己开启网络服务。
另外,将start选项改为stop和restart分别是停止服务和重启服务,改为enable表示加入开机启动列表。
一键启动脚本
因为是学习阶段,出现各种错误老是需要开开关关,所以写了一个一键启动的脚本。
创建service-list.txt文件,按顺序写上所有需要启动的服务名称:
etcd
docker
kube-apiserver
kube-controller-manager
kube-scheduler
kubelet
kube-proxy
创建脚本文件k8s-service-start.sh:
#!/bin/bash
for SERVNAME in `cat service-list.txt`
do
systemctl status $SERVNAME &> /dev/null
if [ $? -eq 0 ]
then
echo "Already Active : $SERVNAME"
else
systemctl start $SERVNAME
systemctl status $SERVNAME &> /dev/null
if [ $? -eq 0 ]
then
echo "Start Success : $SERVNAME"
else
echo "! Start fail : $SERVNAME"
fi
fi
done
记得给脚本加上执行权限:
chmod +x k8s-service-start.sh
当然,如果已经使用systemctl enable加入了开机启动就无需重复操作了。
一般从官方网站下载Docker镜像都比较慢,所以设置一下国内源进行镜像加速。
在/etc/docker/daemon.json 中写入如下内容(如果文件不存在请新建该文件):
{"registry-mirrors":["你的镜像加速地址"]}
我使用的是阿里云源,在阿里云账号的“容器镜像服务 - 镜像中心 - 镜像加速器”菜单中可以找到你专属的镜像加速地址。
你也可以使用其他地址:
网易:https://hub-mirror.c.163.com/
七牛云:https://reg-mirror.qiniu.com
之后重启docker服务:
systemctl daemon-reload
systemctl restart docker
以上都是安装和配置,下面正式进入到kubernetes的使用了。
首先最好新建一个工作文件夹,方便管理。
在工作文件夹下新建RC定义文件mysql-rc.yaml,内容如下:
apiVersion: v1
kind: ReplicationController
metadata:
name: mysql
spec:
replicas: 1
selector:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7 #若不加版本号5.7,可能会导致错误
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
这里yaml文件中的kind属性,用来表示资源对象的类型,比如这里就表示一个RC。(最外层的)spec一节表示RC的相关属性定义,如replicas表示期望实例数量,template是创建POD实例的模板。注意template中的labels必须与前面的selector匹配。
原版书的spec.containers.image没有写版本号,默认拉取latest镜像,这可能会导致一些不兼容的错误。笔者使用5.7版本没有问题。
另外注意缩进要正确。
新建Service定义文件mysql-svc.yaml,内容如下:
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
selector:
app: mysql
文件编写完毕后,就可以启动Service和发布RC了。
kubectl create -f mysql-svc.yaml
# 正确输出:service "mysql" created
此外对应地,可以用如下命令删除服务:
kubectl delete -f mysql-svc.yaml
kubectl get svc
# 正确输出:
# NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# kubernetes 10.254.0.1 <none> 443/TCP 2d
# mysql 10.254.21.86 <none> 3306/TCP 17h
其中CLUSTER-IP是kubernetes为POD自动分配的集群内IP,与宿主机无关(且与宿主机网段不能重合)。
kubectl create -f mysql-rc.yaml
# 正确输出:replicationcontroller "mysql" created
kubectl get rc
# 正确输出,READY应为1:
# NAME DESIRED CURRENT READY AGE
# mysql 1 1 1 17h
查看POD状态:
kubectl get pods
# 正确输出,READY应为1,STATUS应为Running:
# NAME READY STATUS RESTARTS AGE
# mysql-8811b 1/1 Running 1 17h
如果STATUS为Pending或ContainerCreating,说明还在下载或创建容器,可以等待片刻。如果长时间处于此状态,或者状态变为CrashLoopBackOff或Error,说明出现了某些错误。可以检查一下所有的服务是否已开启,yaml文件编写有无错误(拼写、缩进、多余的空格等)。
读者可能注意到,之前是先编写rc文件再编写svc文件的,但此处是先创建Service再发布RC。实际上,《指南》中是先发布RC再创建Service的,但有博客说这样启动出现了一些问题(虽然不是这个例子),因此这里先创建Service再发布RC。
上一节定义和启动了MySQL服务,这里用同样的步骤启动Tomcat,也就是Web应用。
创建myweb-rc.yaml文件,内容如下:
kind: ReplicationController
metadata:
name: myweb
spec:
replicas: 5
selector:
app: myweb
template:
metadata:
labels:
app: myweb
spec:
containers:
- name: myweb
image: kubeguide/tomcat-app:v1
ports:
- containerPort: 8080
env:
- name: MYSQL_SERVICE_HOST
# value: 'mysql'
value: 10.254.21.86 # 这里很坑,集群尚未启动域名解析服务,需要直接填写mysql服务的IP地址
- name: MYSQL_SERVICE_PORT
value: '3306'
这个文件也很关键,按照《指南》里写可能会出错。坑点是MYSQL_SERVICE_HOST的值要直接写mysql服务的IP地址,也就是之前使用kubectl get svc命令查看到的mysql的IP。
当然,真正应用时一定不会这么做,因为某个POD是有可能挂掉的,下次启动时IP可能就会变。但是在刚刚入门时啥都不懂的情况下,这样做是最快的,否则搞了半天看不到成功结果,是非常打击学习兴趣和信心的(笔者就是QwQ)。
创建myweb-svc.yaml文件,内容如下:
apiVersion: v1
kind: Service
metadata:
name: myweb
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30001
selector:
app: myweb
发布Service:
kubectl create -f myweb-svc.yaml
# 正确输出:service "myweb" created
发布RC:
kubectl create -f myweb-rc.yaml
# 正确输出:replicationcontroller "myweb" created
同样地,可以用kubectl get命令来查看各种资源的状态。
终于到了激动人心的时刻,配置完毕,可以开始访问网站了。
使用物理机的浏览器访问:
如果成功,你会看到如下页面:

点击“Add...”可以增加记录。
如果不能访问,就用虚拟机自己的浏览器来访问。如果虚拟机可以访问,那么很可能是防火墙的问题,需要关闭后重启kubernetes相关服务,再执行命令:
iptables -P FORWARD ACCEPT
如果还是不能解决,也许你要从头开始检查每个步骤,甚至可能遇到笔者未遇到的错误。假如下面一节的方法都不能解决你的问题,那么笔者也无能为力了orz!
Good luck!_
总结一下笔者踩到的坑。当然也不一定就是关键的错误,但下面的方案笔者都试过。
使用下面的命令查看pods的日志,可能有助于定位错误:
kubectl logs POD名
现象
可以访问网页,但浏览器显示报错:
Error:com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
解决方案
有2种可能性:
对于1,删除mysql的RC资源,将mysql-rc.yaml中的image参数改为mysql:5.7后重新发布。
对于2,将myweb-rc.yaml中MYSQL_SERVICE_HOST的value改为mysql服务的IP地址,也就是用kubectl get svc查看到的地址,重新发布RC。
现象
物理机无法访问网页,但虚拟机可以。
解决方案
systemctl status firewalld
systemctl disable firewalld #禁止防火墙开机启动
systemctl stop firewalld #关闭防火墙服务
重启kubernetes相关服务
执行以下命令:
iptables -P FORWARD ACCEPT
现象
启动kube-apiserver报错:
Job for kube-apiserver.service failed because the control process exited with error code. See "systemctl status kube-apiserver.service" and "journalctl -xe" for details.
解决方案
首先打开CentOS自己的网络连接,再启动kube-apiserver。
现象
RC的状态卡在ContainerCreating/Pending,或变成CrashLoopBackOff/Error。
解决方案
检查rc的yaml文件有无错误,包括拼写、缩进、多余的空格等。
如果文件编写无误,尝试更换Docker国内镜像源或kexue上网。
现象
其他报错,或者看不到报错,但虚拟机和物理机都不能访问。
解决方案
按照本文从头检查所有步骤,若仍然有错可以尝试:
参考资料:
k8s中部署 Tomcat+MySQL服务
在k8s中定义和启动mysql和tomcat服务之后,浏览器无法访问的问题
出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在
如何使用RSpec::Core::RakeTask初始化RSpecRake任务?require'rspec/core/rake_task'RSpec::Core::RakeTask.newdo|t|#whatdoIputinhere?endInitialize函数记录在http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/RakeTask#initialize-instance_method没有很好的记录;它只是说:-(RakeTask)initialize(*args,&task_block)AnewinstanceofRake
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?
我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法
我正在尝试按0-9和a-z的顺序创建数字和字母列表。我有一组值value_array=['0','1','2','3','4','5','6','7','8','9','a','b','光盘','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','','u','v','w','x','y','z']和一个组合列表的数组,按顺序,这些数字可以产生x个字符,比方说三个list_array=[]和一个当前字母和数字组合的数组(在将它插入列表数组之前我会把它变成一个字符串,]current_combo['0','0','0']
文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/