前言 本文会以最简单、最直接、最完整的方式记录kubernetes(下面统称K8S)单master多工作节点(workernodes)的集群步骤基本概念 首先要简单了解一下本文的3个核心概念:Kubelet:K8S工作节点上的重要组件,它的作用是管理Pod,引用官方的一句描述ThekubeletworksintermsofaPodSpec;Kubeadm:官方提供的快速创建集群工具;Kubectl:kubectl是K8S的命令行工具,可以管理集群。工作流程我们的工作流程分三大步安装Kubeadm创建集群安装dashboard第一步安装Kubeadm环境准备 Linux主机,配置要求至少拥有2CPU和2GB的内存,本文使用的系统版本是CentOS7。6 内存建议至少4G 为了完成集群的测试,应准备2台或2台以上的主机,本文使用1台master和2台work 集群中所有机器的网络连接都是完整的(公网或者内网都可以) 每个节点拥有唯一主机名、MAC地址和productuuid 问:如何查看主机名? 答:执行命令hostname 问:如何修改主机名? 答:永久生效的做法:执行命令vietchostname,把第一行去掉(不能注释掉,要去掉),然后重新写上自定义的主机名(注意命名规范),保存并重启后生效; 临时生效的做法:执行以下命令hostname你自定义的主机名 问:如何查看MAC地址? 答:执行命令iplink,然后看你的第一网卡 问:如何查看productuuid? 答:执行命令sudocatsysclassdmiidproductuuid 根据你对不同组件的使用情况需要开放以下端口,并使用telnet测试端口是否打开(如果目的只是为了测试或者条件允许的情况下,直接关闭防火墙即可)master主机(又称为控制平面或者Controlplane)需要打开的端口 Protocol 方向 PortRange Purpose UsedBy TCP 入站 6443hrKubernetesAPIserver All TCP 入站 23792380 etcdserverclientAPI kubeapiserver,etcd TCP 入站 10250hrKubeletAPI Self,Controlplane TCP 入站 10259hrkubescheduler Self TCP 入站 10257hrkubecontrollermanager Self工作节点(又称为workerNode)需要打开的端口 Protocol 方向 PortRange Purpose UsedBy TCP 入站 10250hrKubeletAPI Self,Controlplane TCP 入站 3000032767 NodePortServices All 注意:3000032767这个端口范围是我们创建服务的端口必须要设置的一个范围(如果设置范围以外的会有限制提示并创建失败),这是K8S规定的。 另外,如果你要直接关闭防火墙可以执行systemctlstopfirewalld。servicesystemctldisablefirewalld。service 必须禁用Swap〔roottestmachine01〕freetotalusedfreesharedbuffcacheavailableMem:186325275961692032257361011604818296Swap:209817202098172 Swaptotal大于0,说明Swap分区是开启的 问:如何关闭Swap? 答:编辑文件etcfstab,在swap行前面加上号注释,保存并重启服务器〔roottestmachine01〕vietcfstabUUIDfa5df00e8eb84fd19376ccfc15e32848swapswapdefaults00 再次查看分区状态,已生效〔roottestmachine01〕freetotalusedfreesharedbuffcacheavailableMem:1863252726388123116309681013748848484Swap:000 安装容器引擎 常见的容器引擎(Containerruntime,简称runtime):containerdCRIODocker 本文使用的容器引擎是Docker 安装命令sudoyuminstallyyumutilssudoyumconfigmanageraddrepohttps:download。docker。comlinuxcentosdockerce。reposudoyuminstallydockercedockerceclicontainerd。iosystemctlstartdockersystemctlenabledocker。service 安装完成后查看版本:〔roottestmachine01〕dockervDockerversion20。10。11,builddea9396 如果需要删除旧版本sudoyumremovedockerdockerclientdockerclientlatestdockercommondockerlatestdockerlatestlogrotatedockerlogrotatedockerengine 如果需要卸载Docker引擎 当出现可能跟Docker引擎相关的奇怪异常时可以尝试把Docker卸载干净并重新安装,但一定要注意镜像、容器、卷或配置文件这些是否需要备份。 下面记录卸载Docker引擎的步骤: 卸载DockerEngine、CLI和Containerd包:sudoyumremovedockercedockerceclicontainerd。io 主机上的映像、容器、卷或自定义配置文件不会自动删除。删除所有镜像、容器和卷:sudormrfvarlibdockersudormrfvarlibcontainerd 配置文件如果有不合法的字符时会导致启动失败,我们需要将其删除然后重建〔roottestmachine01〕rmrfetcdockerdaemon。json 此时Docker引擎已卸载干净 安装kubeadm,kubeletandkubectl 安装yum源catEOFsudoteeetcyum。repos。dkubernetes。repo〔kubernetes〕nameKubernetesbaseurlhttps:mirrors。aliyun。comkubernetesyumreposkubernetesel7x8664enabled1gpgcheck1repogpgcheck1gpgkeyhttps:mirrors。aliyun。comkubernetesyumdocyumkey。gpghttps:mirrors。aliyun。comkubernetesyumdocrpmpackagekey。gpgexcludekubeletkubeadmkubectlEOF 官网用的是谷歌的yum源,因为国内是连不上的,所以这里替换成阿里提供的yum源 禁用SELinux〔roottestmachine01〕sudosetenforce0sudosedisSELINUXenforcingSELINUXpermissiveetcselinuxconfig 安装和启动 安装sudoyuminstallykubeletkubeadmkubectldisableexcludeskubernetes 从安装信息中可以看到版本号是1。22 Installing: kubeadmx86641。22。40kubernetes9。3M kubectlx86641。22。40kubernetes9。7M kubeletx86641。22。40kubernetes20M 启动〔roottestmachine01〕sudosystemctlenablenowkubeletCreatedsymlinkfrometcsystemdsystemmultiuser。target。wantskubelet。servicetousrlibsystemdsystemkubelet。service。 让iptables看到桥接流量catEOFsudoteeetcmodulesload。dk8s。confbrnetfilterEOFcatEOFsudoteeetcsysctl。dk8s。confnet。bridge。bridgenfcallip6tables1net。bridge。bridgenfcalliptables1EOFsudosysctlsystem 配置cgroup驱动程序 这就是一个驱动程序,注意cgroup和cgroupfs不要混淆了 引用官方的一段话 由于kubeadm把kubelet视为一个系统服务来管理,所以对基于kubeadm的安装,我们推荐使用systemd驱动,不推荐cgroupfs驱动。 kubeadm默认是使用systemd驱动,而我们的Docker默认驱动是cgroupfs(dockerinfo可以查看),所以需要将Docker的驱动改成systemd 编辑Docker配置文件〔roottestmachine01〕vietcdockerdaemon。json{execopts:〔native。cgroupdriversystemd〕} 重启Docker服务〔roottestmachine01〕systemctldaemonreloadsystemctlrestartdocker 再次dockerinfo查看驱动信息已变成了systemd 工作节点(workernodes)的最小配置就到这里了 第二步创建集群 镜像源参数说明 默认情况下,kubeadm会从k8s。gcr。io仓库拉取镜像,国内是拉不了的。官方文档明确表示允许你使用其他的imageRepository来代替k8s。gcr。io。 imagerepository你的镜像仓库地址 接下来我找了一些国内的镜像源,并简单做了下分析 可访问站点 搜索结果 推荐程度 华为云 没有 阿里云用户公开镜像,但一直在持续更新,新版本的都有 https:cr。console。aliyun。comimagescnhangzhougooglecontainerskubecontrollermanagerdetail 比较推荐 dockerhub 个人用户上传,版本很旧 不推荐 百度云 没有 腾讯云 个人用户上传,版本很旧 不推荐 自建 条件允许的情况下,自建是比较好的,但有一定的成本 推荐 综合上述统计,我选择阿里云的镜像源 ip地址范围参数说明 podnetworkcidr192。168。0。016 注意:如果192。168。0。016已经在您的网络中使用,您必须选择一个不同的pod网络CIDR,在上面的命令中替换192。168。0。016。集群初始化 集群初始化命令:kubeadminitimagerepository你的镜像仓库地址podnetworkcidr你的ip地址范围 因为我用的是演示机器,所以这里把完整的执行信息都贴出来方便查阅,平时工作中一定要注意保护好敏感的信息(我的ip地址范围是自定义的便于下面的功能演示,另外初次init需要下载镜像文件,一般需要等几分钟)〔roottestmachine01〕kubeadminitimagerepositoryregistry。cnhangzhou。aliyuncs。comgooglecontainerspodnetworkcidr192。100。0。016〔init〕UsingKubernetesversion:v1。22。4〔preflight〕Runningpreflightchecks〔preflight〕PullingimagesrequiredforsettingupaKubernetescluster〔preflight〕Thismighttakeaminuteortwo,dependingonthespeedofyourinternetconnection〔preflight〕Youcanalsoperformthisactioninbeforehandusingkubeadmconfigimagespull〔certs〕UsingcertificateDirfolderetckubernetespki〔certs〕Generatingcacertificateandkey〔certs〕Generatingapiservercertificateandkey〔certs〕apiserverservingcertissignedforDNSnames〔kuberneteskubernetes。defaultkubernetes。default。svckubernetes。default。svc。cluster。localtestmachine01〕andIPs〔10。96。0。1192。168。189。128〕〔certs〕Generatingapiserverkubeletclientcertificateandkey〔certs〕Generatingfrontproxycacertificateandkey〔certs〕Generatingfrontproxyclientcertificateandkey〔certs〕Generatingetcdcacertificateandkey〔certs〕Generatingetcdservercertificateandkey〔certs〕etcdserverservingcertissignedforDNSnames〔localhosttestmachine01〕andIPs〔192。168。189。128127。0。0。1::1〕〔certs〕Generatingetcdpeercertificateandkey〔certs〕etcdpeerservingcertissignedforDNSnames〔localhosttestmachine01〕andIPs〔192。168。189。128127。0。0。1::1〕〔certs〕Generatingetcdhealthcheckclientcertificateandkey〔certs〕Generatingapiserveretcdclientcertificateandkey〔certs〕Generatingsakeyandpublickey〔kubeconfig〕Usingkubeconfigfolderetckubernetes〔kubeconfig〕Writingadmin。confkubeconfigfile〔kubeconfig〕Writingkubelet。confkubeconfigfile〔kubeconfig〕Writingcontrollermanager。confkubeconfigfile〔kubeconfig〕Writingscheduler。confkubeconfigfile〔kubeletstart〕Writingkubeletenvironmentfilewithflagstofilevarlibkubeletkubeadmflags。env〔kubeletstart〕Writingkubeletconfigurationtofilevarlibkubeletconfig。yaml〔kubeletstart〕Startingthekubelet〔controlplane〕Usingmanifestfolderetckubernetesmanifests〔controlplane〕CreatingstaticPodmanifestforkubeapiserver〔controlplane〕CreatingstaticPodmanifestforkubecontrollermanager〔controlplane〕CreatingstaticPodmanifestforkubescheduler〔etcd〕CreatingstaticPodmanifestforlocaletcdinetckubernetesmanifests〔waitcontrolplane〕WaitingforthekubelettobootupthecontrolplaneasstaticPodsfromdirectoryetckubernetesmanifests。Thiscantakeupto4m0s〔apiclient〕Allcontrolplanecomponentsarehealthyafter31。006106seconds〔uploadconfig〕StoringtheconfigurationusedinConfigMapkubeadmconfiginthekubesystemNamespace〔kubelet〕CreatingaConfigMapkubeletconfig1。22innamespacekubesystemwiththeconfigurationforthekubeletsinthecluster〔uploadcerts〕Skippingphase。Pleaseseeuploadcerts〔markcontrolplane〕Markingthenodetestmachine01ascontrolplanebyaddingthelabels:〔noderole。kubernetes。iomaster(deprecated)noderole。kubernetes。iocontrolplanenode。kubernetes。ioexcludefromexternalloadbalancers〕〔markcontrolplane〕Markingthenodetestmachine01ascontrolplanebyaddingthetaints〔noderole。kubernetes。iomaster:NoSchedule〕〔bootstraptoken〕Usingtoken:nhsbf0。r3wr6iyd3ico6sox〔bootstraptoken〕Configuringbootstraptokens,clusterinfoConfigMap,RBACRoles〔bootstraptoken〕configuredRBACrulestoallowNodeBootstraptokenstogetnodes〔bootstraptoken〕configuredRBACrulestoallowNodeBootstraptokenstopostCSRsinorderfornodestogetlongtermcertificatecredentials〔bootstraptoken〕configuredRBACrulestoallowthecsrapprovercontrollerautomaticallyapproveCSRsfromaNodeBootstrapToken〔bootstraptoken〕configuredRBACrulestoallowcertificaterotationforallnodeclientcertificatesinthecluster〔bootstraptoken〕CreatingtheclusterinfoConfigMapinthekubepublicnamespace〔kubeletfinalize〕Updatingetckuberneteskubelet。conftopointtoarotatablekubeletclientcertificateandkey〔addons〕Appliedessentialaddon:CoreDNS〔addons〕Appliedessentialaddon:kubeproxyYourKubernetescontrolplanehasinitializedsuccessfully!步骤1:用户配置Tostartusingyourcluster,youneedtorunthefollowingasaregularuser:mkdirpHOME。kubesudocpietckubernetesadmin。confHOME。kubeconfigsudochown(idu):(idg)HOME。kubeconfigAlternatively,ifyouaretherootuser,youcanrun:exportKUBECONFIGetckubernetesadmin。conf步骤2:网络配置Youshouldnowdeployapodnetworktothecluster。Runkubectlapplyf〔podnetwork〕。yamlwithoneoftheoptionslistedat:https:kubernetes。iodocsconceptsclusteradministrationaddons步骤3:工作节点加入集群Thenyoucanjoinanynumberofworkernodesbyrunningthefollowingoneachasroot:kubeadmjoin192。168。189。128:6443tokennhsbf0。r3wr6iyd3ico6soxdiscoverytokencacerthashsha256:0ab5863d0b42a36e8ef04f174106a9ccfb6927fba3c884052d5a2c9e0de76185 如上所示,集群初始化成功,此时一定要注意看上面执行结果最后的那部分操作提示,我已用标明了初始化成功后还需要执行的3个步骤 注意:如果init成功后发现参数需要调整,可以执行kubeadmreset,它的作用是尽最大努力恢复kubeadminit或者kubeadmjoin所做的更改。用户配置 Tostartusingyourcluster,youneedtorunthefollowingasaregularuser: 翻译:开始使用集群前,如果你是普通用户(非root),你需要执行以下的命令:mkdirpHOME。kubesudocpietckubernetesadmin。confHOME。kubeconfigsudochown(idu):(idg)HOME。kubeconfig Alternatively,ifyouaretherootuser,youcanrun: 翻译:或者,如果你使用的是root,你可以执行以下命令: (注意:export只是临时生效,意味着每次登录你都需要执行一次)exportKUBECONFIGetckubernetesadmin。conf网络配置 网络配置配的就是Pod的网络,我的网络插件选用calico 下载KubernetesAPI数据存储的Calico网络清单〔roottestmachine01〕curlhttps:docs。projectcalico。orgmanifestscalico。yamlOTotalReceivedXferdAverageSpeedTimeTimeTimeCurrentDloadUploadTotalSpentLeftSpeed100212k100212k009625500:00:020:00:02::96292 修改CIDR cidr就是ip地址范围,如果您使用podCIDR192。168。0。016,请跳到下一步。 但本文中使用的podCIDR是192。100。0。016,所以我需要取消对清单中的CALICOIPV4POOLCIDR变量的注释,并将其设置为与我选择的podCIDR相同的值。(注意一定要注意好格式,注意对齐) 根据需要自定义清单 可根据需求自定义清单,一般不需要的就直接跳过这步 应用清单〔roottestmachine01〕kubectlapplyfcalico。yaml 为了使Nodes之间的Pod可以相互访问,内核必须开启ip转发(内核将处理桥接容器的数据包) 内核参数配置〔roottestmachine01〕vietcsysctl。confnet。ipv4。ipforward1net。bridge。bridgenfcallip6tables1net。bridge。bridgenfcalliptables1 使新的内核参数生效sysctlp工作节点加入集群 在所有的工作节点上执行join命令(复制之前初始化成功后返回的加入集群命令到所有的工作节点执行即可)〔roottestmachine03〕kubeadmjoin192。168。189。128:6443tokennhsbf0。r3wr6iyd3ico6soxdiscoverytokencacerthashsha256:0ab5863d0b42a36e8ef04f174106a9ccfb6927fba3c884052d5a2c9e0de76185〔preflight〕Runningpreflightchecks〔preflight〕Readingconfigurationfromthecluster。。。〔preflight〕FYI:Youcanlookatthisconfigfilewithkubectlnkubesystemgetcmkubeadmconfigoyaml〔kubeletstart〕Writingkubeletconfigurationtofilevarlibkubeletconfig。yaml〔kubeletstart〕Writingkubeletenvironmentfilewithflagstofilevarlibkubeletkubeadmflags。env〔kubeletstart〕Startingthekubelet〔kubeletstart〕WaitingforthekubelettoperformtheTLSBootstrap。。。Thisnodehasjoinedthecluster:Certificatesigningrequestwassenttoapiserverandaresponsewasreceived。TheKubeletwasinformedofthenewsecureconnectiondetails。Runkubectlgetnodesonthecontrolplanetoseethisnodejointhecluster。 master上查看所有节点的状态〔roottestmachine01〕kubectlgetnodesowideNAMESTATUSROLESAGEVERSIONINTERNALIPEXTERNALIPOSIMAGEKERNELVERSIONCONTAINERRUNTIMEtestmachine01Readycontrolplane,master6h7mv1。22。4192。168。189。128noneCentOSLinux7(Core)3。10。0957。el7。x8664docker:20。10。11testmachine02Readynone59mv1。22。4192。168。189。130noneCentOSLinux7(Core)3。10。0957。el7。x8664docker:20。10。11testmachine03Readynone17mv1。22。4192。168。189。131noneCentOSLinux7(Core)3。10。0957。el7。x8664docker:20。10。11 到这里集群已经创建完成 最后一步安装dashboard 最后我再安装K8S的可视化界面kubernetesdashboard,方便我们日常使用 下载yaml文件wgethttps:raw。githubusercontent。comkubernetesdashboardv2。4。0aiodeployrecommended。yamlnocheckcertificate 修改yaml文件,新增type和nodePort,使服务能够被外部访问〔roottestmachine01〕virecommended。yamlkind:ServiceapiVersion:v1metadata:labels:k8sapp:kubernetesdashboardname:kubernetesdashboardnamespace:kubernetesdashboardspec:type:NodePortports:port:443targetPort:8443nodePort:31437selector:k8sapp:kubernetesdashboard 安装并查看运行情况〔roottestmachine01〕kubectlapplyfrecommended。yaml〔roottestmachine01〕watchkubectlgetpodsnkubernetesdashboard 新建用户〔roottestmachine01〕vidashboardadminuser。yamlapiVersion:v1kind:ServiceAccountmetadata:name:adminusernamespace:kubernetesdashboardapiVersion:rbac。authorization。k8s。iov1kind:ClusterRoleBindingmetadata:name:adminuserroleRef:apiGroup:rbac。authorization。k8s。iokind:ClusterRolename:clusteradminsubjects:kind:ServiceAccountname:adminusernamespace:kubernetesdashboard 文件创建完成后保存并applykubectlapplyfdashboardadminuser。yaml 获取Token,用于界面登录kubectlnkubernetesdashboardgetsecret(kubectlnkubernetesdashboardgetsaadminuserojsonpath{。secrets〔0〕。name})ogotemplate{{。data。tokenbase64decode}} 登录dashboard 192。168。189。128是我的master服务器ip,另外要注意必须使用https,并且不能使用ie内核模式 复制生成的token到输入框,点击登录 dashboard安装配置完成 QA 问:如何在查看资源情况? 答:在master上执行以下命令可查看资源情况(owide是显示更详细的信息), 查看所有节点kubectlgetnodesowide 查看所有命名空间kubectlgetnamespacesowide 查看命名空间下的podkubectlgetpodsn你的命名空间owide 查看所有命名空间的podkubectlgetpodsallnamespacesowide 实时查看查看命名空间下的pod运行情况watchkubectlgetpodsn你的命名空间 问:kubeadmjoin出现异常〔ERRORPort10250〕:Port10250isinuse,如何解决? 答:这是因为你之前join失败过了,需要先执行kubeadmreset再重新join 问:虚拟机上测试时网卡突然消失如何解决(题外问题记录)? 答: 确认丢失的网卡信息,ens开头(可选步骤) ifconfiga 执行以下命令解决systemctlstopNetworkManagersystemctldisableNetworkManagersystemctlrestartnetwork。serviceservicenetworkrestart 问:如何查看K8S版本? 答:kubectlversion 问:join命令忘记或者过期了怎么办? 答: 生成永不过期的kubeadmtokencreatettl0printjoincommand 生成时效24小时的kubeadmtokencreateprintjoincommand 问:Pod不断重启并且无其它报错信息时怎么办? 答:这种情况通常是因为你的集群中只有master,没有worker节点,master的创建默认是有污点的,即不允许调度新的Pod,如果你需要(当然这并不推荐),就需要删除master上的污点。删除污点可以执行以下命令,kubectltaintnodesallnoderole。kubernetes。iomaster 它应该返回以下内容。nodeyourhostnameuntainted