mirror of
https://github.com/zhwei820/learn.lianglianglee.com.git
synced 2025-09-17 08:46:40 +08:00
1090 lines
46 KiB
HTML
1090 lines
46 KiB
HTML
<!DOCTYPE html>
|
||
|
||
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
|
||
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
|
||
<head>
|
||
|
||
<head>
|
||
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
|
||
|
||
<link rel="icon" href="/static/favicon.png">
|
||
|
||
<title>05 动手实践:搭建一个 Kubernetes 集群 - 生产可用.md.html</title>
|
||
|
||
<!-- Spectre.css framework -->
|
||
|
||
<link rel="stylesheet" href="/static/index.css">
|
||
|
||
<!-- theme css & js -->
|
||
|
||
<meta name="generator" content="Hexo 4.2.0">
|
||
|
||
</head>
|
||
<body>
|
||
<div class="book-container">
|
||
|
||
<div class="book-sidebar">
|
||
|
||
<div class="book-brand">
|
||
|
||
<a href="/">
|
||
|
||
<img src="/static/favicon.png">
|
||
|
||
<span>技术文章摘抄</span>
|
||
|
||
</a>
|
||
|
||
</div>
|
||
|
||
<div class="book-menu uncollapsible">
|
||
|
||
<ul class="uncollapsible">
|
||
|
||
<li><a href="/" class="current-tab">首页</a></li>
|
||
|
||
</ul>
|
||
<ul class="uncollapsible">
|
||
|
||
<li><a href="../">上一级</a></li>
|
||
|
||
</ul>
|
||
<ul class="uncollapsible">
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/01 开篇: Kubernetes 是什么以及为什么需要它.md.html">01 开篇: Kubernetes 是什么以及为什么需要它.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/02 初步认识:Kubernetes 基础概念.md.html">02 初步认识:Kubernetes 基础概念.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/03 宏观认识:整体架构.md.html">03 宏观认识:整体架构.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/04 搭建 Kubernetes 集群 - 本地快速搭建.md.html">04 搭建 Kubernetes 集群 - 本地快速搭建.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
<a class="current-tab" href="/专栏/Kubernetes 从上手到实践/05 动手实践:搭建一个 Kubernetes 集群 - 生产可用.md.html">05 动手实践:搭建一个 Kubernetes 集群 - 生产可用.md.html</a>
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/06 集群管理:初识 kubectl.md.html">06 集群管理:初识 kubectl.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/07 集群管理:以 Redis 为例-部署及访问.md.html">07 集群管理:以 Redis 为例-部署及访问.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/08 安全重点 认证和授权.md.html">08 安全重点 认证和授权.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/09 应用发布:部署实际项目.md.html">09 应用发布:部署实际项目.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/10 应用管理:初识 Helm.md.html">10 应用管理:初识 Helm.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/11 部署实践:以 Helm 部署项目.md.html">11 部署实践:以 Helm 部署项目.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/12 庖丁解牛:kube-apiserver.md.html">12 庖丁解牛:kube-apiserver.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/13 庖丁解牛:etcd.md.html">13 庖丁解牛:etcd.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/14 庖丁解牛:controller-manager.md.html">14 庖丁解牛:controller-manager.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/15 庖丁解牛:kube-scheduler.md.html">15 庖丁解牛:kube-scheduler.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/16 庖丁解牛:kubelet.md.html">16 庖丁解牛:kubelet.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/17 庖丁解牛:kube-proxy.md.html">17 庖丁解牛:kube-proxy.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/18 庖丁解牛:Container Runtime (Docker).md.html">18 庖丁解牛:Container Runtime (Docker).md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/19 Troubleshoot.md.html">19 Troubleshoot.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/20 扩展增强:Dashboard.md.html">20 扩展增强:Dashboard.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/21 扩展增强:CoreDNS.md.html">21 扩展增强:CoreDNS.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/22 服务增强:Ingress.md.html">22 服务增强:Ingress.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/23 监控实践:对 K8S 集群进行监控.md.html">23 监控实践:对 K8S 集群进行监控.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/24 总结.md.html">24 总结.md.html</a>
|
||
</li>
|
||
|
||
</ul>
|
||
</div>
|
||
|
||
</div>
|
||
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
|
||
|
||
<div class="sidebar-toggle-inner"></div>
|
||
|
||
</div>
|
||
<script>
|
||
|
||
function add_inner() {
|
||
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
|
||
inner.classList.add('show')
|
||
|
||
}
|
||
function remove_inner() {
|
||
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
|
||
inner.classList.remove('show')
|
||
|
||
}
|
||
function sidebar_toggle() {
|
||
|
||
let sidebar_toggle = document.querySelector('.sidebar-toggle')
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let content = document.querySelector('.off-canvas-content')
|
||
|
||
if (sidebar_toggle.classList.contains('extend')) { // show
|
||
|
||
sidebar_toggle.classList.remove('extend')
|
||
|
||
sidebar.classList.remove('hide')
|
||
|
||
content.classList.remove('extend')
|
||
|
||
} else { // hide
|
||
|
||
sidebar_toggle.classList.add('extend')
|
||
|
||
sidebar.classList.add('hide')
|
||
|
||
content.classList.add('extend')
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
function open_sidebar() {
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
|
||
sidebar.classList.add('show')
|
||
|
||
overlay.classList.add('show')
|
||
|
||
}
|
||
|
||
function hide_canvas() {
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
|
||
sidebar.classList.remove('show')
|
||
|
||
overlay.classList.remove('show')
|
||
|
||
}
|
||
</script>
|
||
<div class="off-canvas-content">
|
||
|
||
<div class="columns">
|
||
|
||
<div class="column col-12 col-lg-12">
|
||
|
||
<div class="book-navbar">
|
||
|
||
<!-- For Responsive Layout -->
|
||
|
||
<header class="navbar">
|
||
|
||
<section class="navbar-section">
|
||
|
||
<a onclick="open_sidebar()">
|
||
|
||
<i class="icon icon-menu"></i>
|
||
|
||
</a>
|
||
|
||
</section>
|
||
|
||
</header>
|
||
|
||
</div>
|
||
|
||
<div class="book-content" style="max-width: 960px; margin: 0 auto;
|
||
|
||
overflow-x: auto;
|
||
|
||
overflow-y: hidden;">
|
||
|
||
<div class="book-post">
|
||
|
||
<p id="tip" align="center"></p>
|
||
|
||
<div><h1>05 动手实践:搭建一个 Kubernetes 集群 - 生产可用</h1>
|
||
|
||
<p>通过上一节的学习,我们快速的使用 <code>Minikube</code> 搭建了一个本地可用的 K8S 集群。默认情况下,节点是一个虚拟机实例,我们可以在上面体验一些基本的功能。</p>
|
||
|
||
<p>大多数人的需求并不只是包含一个虚拟机节点的本地测试集群,而是一个可在服务器运行,可自行扩/缩容,具备全部功能的,达到生产可用的集群。</p>
|
||
|
||
<p>K8S 集群的搭建,一直让很多人头疼,本节我们来搭建一个生产可用的集群,便于后续的学习或使用。</p>
|
||
|
||
<h2>方案选择</h2>
|
||
|
||
<p>K8S 生产环境可用的集群方案有很多,本节我们选择一个 Kubernetes 官方推荐的方案 <code>kubeadm</code> 进行搭建。</p>
|
||
|
||
<p><code>kubeadm</code> 是 Kubernetes 官方提供的一个 CLI 工具,可以很方便的搭建一套符合官方最佳实践的最小化可用集群。当我们使用 <code>kubeadm</code> 搭建集群时,集群可以通过 K8S 的一致性测试,并且 <code>kubeadm</code> 还支持其他的集群生命周期功能,比如升级/降级等。</p>
|
||
|
||
<p>我们在此处选择 <code>kubeadm</code> ,因为我们可以不用过于关注集群的内部细节,便可以快速的搭建出生产可用的集群。我们可以通过后续章节的学习,快速上手 K8S ,并学习到 K8S 的内部原理。在此基础上,想要在物理机上完全一步步搭建集群,便轻而易举。</p>
|
||
|
||
<h2>安装基础组件</h2>
|
||
|
||
<h3>前期准备</h3>
|
||
|
||
<p>使用 <code>kubeadm</code> 前,我们需要提前做一些准备。</p>
|
||
|
||
<ul>
|
||
|
||
<li>
|
||
|
||
<p><strong>我们需要禁用 swap</strong>。通过之前的学习,我们知道每个节点上都有个必须的组件,名为 <code>kubelet</code>,自 K8S 1.8 开始,启动 <code>kubelet</code> 时,需要禁用 <code>swap</code> 。或者需要更改 <code>kubelet</code> 的启动参数 <code>--fail-swap-on=false</code>。</p>
|
||
|
||
<p>虽说可以更改参数让其可用,但是我建议还是禁用 <code>swap</code> 除非你的集群有特殊的需求,比如:有大内存使用的需求,但又想节约成本;或者你知道你将要做什么,否则可能会出现一些非预期的情况,尤其是做了内存限制的时候,当某个 Pod 达到内存限制的时候,它可能会溢出到 swap 中,这会导致 K8S 无法正常进行调度。</p>
|
||
|
||
<p>如何禁用:</p>
|
||
|
||
<ol>
|
||
|
||
<li>使用 <code>sudo cat /proc/swaps</code> 验证 swap 配置的设备和文件。</li>
|
||
|
||
<li>通过 <code>swapoff -a</code> 关闭 swap 。</li>
|
||
|
||
<li>使用 <code>sudo blkid</code> 或者 <code>sudo lsblk</code> 可查看到我们的设备属性,请注意输出结果中带有 <code>swap</code> 字样的信息。</li>
|
||
|
||
<li>将 <code>/etc/fstab</code> 中和上一条命令中输出的,和 swap 相关的挂载点都删掉,以免在机器重启或重挂载时,再挂载 <code>swap</code> 分区。</li>
|
||
|
||
</ol>
|
||
|
||
<p>执行完上述操作,<code>swap</code> 便会被禁用,当然你也可以再次通过上述命令,或者 <code>free</code> 命令来确认是否还有 <code>swap</code> 存在。</p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7705181803371a1604031205">[email protected]</a> ~]# free
|
||
|
||
total used free shared buff/cache available
|
||
|
||
Mem: 1882748 85608 1614836 16808 182304 1630476
|
||
|
||
Swap: 0 0 0
|
||
|
||
</code></pre>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>通过 <code>sudo cat /sys/class/dmi/id/product_uuid</code> 可查看机器的 <code>product_uuid</code> 请确保要搭建集群的所有节点的 <code>product_uuid</code> 均不相同。同时所有节点的 Mac 地址也不能相同,通过 <code>ip a</code> 或者 <code>ifconfig -a</code> 可进行查看。</p>
|
||
|
||
<p>我们在第二章提到过,每个 Node 都有一些信息会被记录进集群内,而此处我们需要保证的这些唯一的信息,便会记录在集群的 <code>nodeInfo</code> 中,比如 <code>product_uuid</code> 在集群内以 <code>systemUUID</code> 来表示。具体信息我们可以通过集群的 <code>API Server</code> 获取到,在后面的章节会详细讲述。</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>第三章中,我们已经谈过 K8S 是 C/S 架构,在启动后,会固定监听一些端口用于提供服务。可以通过 <code>sudo netstat -ntlp |grep -E '6443|23[79,80]|1025[0,1,2]'</code> 查看这些端口是否被占用,如果被占用,请手动释放。</p>
|
||
|
||
<p>如果你执行上述命令时,提示 <code>command not found</code>,则表明你需要先安装 <code>netstat</code>,在 CentOS 系统中需要通过 <code>sudo yum install net-tools</code> 安装,而在 Debian/Ubuntu 系统中,则需要通过 <code>sudo apt install net-tools</code> 进行安装。</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>前面我们也提到了,我们需要一个容器运行时,通常情况下是 <code>Docker</code>,我们可以通过<a href="https://docs.docker.com/install/overview/">官方的 Docker 文档</a> 进行安装,安装完成后记得启动服务。</p>
|
||
|
||
<p>官方推荐使用 <code>17.03</code> ,但我建议你可以直接安装 <code>18.03</code> 或者更新的版本,因为 <code>17.03</code> 版本的 Docker 已经在 2018 年 3 月 <code>EOL</code>(End Of Life)了。对于更新版本的 Docker,虽然 K8S 尚未在新版本中经过大量测试,但毕竟新版本有很多 Bugfix 和新特性的增加,也能规避一些可能遇到的问题(比如个别情况下 container 不会自动删除的情况 (17.09) )。</p>
|
||
|
||
<p>另外,由于 Docker 的 API 都是带有版本的,且有良好的兼容性,当使用低版本 API 请求时会自动降级,所以一般情况下也不会有什么问题。</p>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
<h3>安装 kubectl</h3>
|
||
|
||
<p>第三章中,我们已经说过 <code>kubectl</code> 是集群的客户端,我们现在搭建集群时,也必须要安装它,用于验证集群功能。</p>
|
||
|
||
<p>安装步骤在第 4 章已经详细说明了,此处不做赘述,可查阅第 4 章或参考下面的内容。</p>
|
||
|
||
<h3>安装 kubeadm 和 kubelet</h3>
|
||
|
||
<p>首先是版本的选择,我们可以通过下面的命令获取到当前的 stable 版本号。要访问这个地址,需要自行处理网络问题或使用我后面提供的解决办法。</p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8dffe2e2f9cde0ecfef9e8ff">[email protected]</a> ~]# curl -sSL https://dl.k8s.io/release/stable.txt
|
||
|
||
v1.11.3
|
||
|
||
</code></pre>
|
||
|
||
<p>下载二进制包,并通过 <code>kubeadm version</code> 验证版本是否正确。</p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4d3f2222390d202c3e39283f">[email protected]</a> ~]# curl -sSL https://dl.k8s.io/release/v1.11.3/bin/linux/amd64/kubeadm > /usr/bin/kubeadm
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b3c1dcdcc7f3ded2c0c7d6c1">[email protected]</a> ~]# chmod a+rx /usr/bin/kubeadm
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e99b86869da984889a9d8c9b">[email protected]</a> ~]# kubeadm version
|
||
|
||
kubeadm version: &version.Info{Major:"1", Minor:"11", GitVersion:"v1.11.3", GitCommit:"a4529464e4629c21224b3d52edfe0ea91b072862", GitTreeState:"clean", BuildDate:"2018-09-09T17:59:42Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}
|
||
|
||
</code></pre>
|
||
|
||
<p>当然,我们其实可以使用如同上一章的方式,直接进入到 <code>kubernetes</code> 的<a href="https://github.com/kubernetes/kubernetes">官方仓库</a>,找到我们所需版本 <a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.11.md#v1113">v1.11.3</a> 下载 <code>Server Binaries</code>,如下图:</p>
|
||
|
||
<p><img src="assets/1660f7b43d86c139" alt="img" /></p>
|
||
|
||
<p>终端下可使用如下方式下载:</p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="61130e0e15210c0012150413">[email protected]</a> tmp]# wget -q https://dl.k8s.io/v1.11.3/kubernetes-server-linux-amd64.tar.gz
|
||
|
||
</code></pre>
|
||
|
||
<p><strong>对于国内用户,我已经准备了下面的方式,方便使用。</strong></p>
|
||
|
||
<pre><code>链接: https://pan.baidu.com/s/1FSEcEUplQQGsjyBIZ6j2fA 提取码: cu4s
|
||
|
||
</code></pre>
|
||
|
||
<p>下载完成后,验证文件是否正确无误,验证通过后进行解压。</p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="097b66667d4964687a7d6c7b">[email protected]</a> tmp]# echo 'e49d0db1791555d73add107d2110d54487df538b35b9dde0c5590ac4c5e9e039 kubernetes-server-linux-amd64.tar.gz' | sha256sum -c -
|
||
|
||
kubernetes-server-linux-amd64.tar.gz: 确定
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4c3e2323380c212d3f38293e">[email protected]</a> tmp]# tar -zxf kubernetes-server-linux-amd64.tar.gz
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b9cbd6d6cdf9d4d8cacddccb">[email protected]</a> tmp]# ls kubernetes
|
||
|
||
addons kubernetes-src.tar.gz LICENSES server
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5b2934342f1b363a282f3e29">[email protected]</a> tmp]# ls kubernetes/server/bin/ | grep -E 'kubeadm|kubelet|kubectl'
|
||
|
||
kubeadm
|
||
|
||
kubectl
|
||
|
||
kubelet
|
||
|
||
</code></pre>
|
||
|
||
<p>可以看到在 <code>server/bin/</code> 目录下有我们所需要的全部内容,将我们所需要的 <code>kubeadm</code> <code>kubectl</code> <code>kubelet</code> 等都移动至 <code>/usr/bin</code> 目录下。</p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="24564b4b5064494557504156">[email protected]</a> tmp]# mv kubernetes/server/bin/kube{adm,ctl,let} /usr/bin/
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f4869b9b80b4999587809186">[email protected]</a> tmp]# ls /usr/bin/kube*
|
||
|
||
/usr/bin/kubeadm /usr/bin/kubectl /usr/bin/kubelet
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c6b4a9a9b286aba7b5b2a3b4">[email protected]</a> tmp]# kubeadm version
|
||
|
||
kubeadm version: &version.Info{Major:"1", Minor:"11", GitVersion:"v1.11.3", GitCommit:"a4529464e4629c21224b3d52edfe0ea91b072862", GitTreeState:"clean", BuildDate:"2018-09-09T17:59:42Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="35475a5a4175585446415047">[email protected]</a> tmp]# kubectl version --client
|
||
|
||
Client Version: version.Info{Major:"1", Minor:"11", GitVersion:"v1.11.3", GitCommit:"a4529464e4629c21224b3d52edfe0ea91b072862", GitTreeState:"clean", BuildDate:"2018-09-09T18:02:47Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7f0d10100b3f121e0c0b1a0d">[email protected]</a> tmp]# kubelet --version
|
||
|
||
Kubernetes v1.11.3
|
||
|
||
</code></pre>
|
||
|
||
<p>可以看到我们所需的组件,版本均为 <code>v1.11.3</code> 。</p>
|
||
|
||
<h2>配置</h2>
|
||
|
||
<p>为了在生产环境中保障各组件的稳定运行,同时也为了便于管理,我们增加对 <code>kubelet</code> 的 <code>systemd</code> 的配置,由 <code>systemd</code> 对服务进行管理。</p>
|
||
|
||
<h3>配置 kubelet</h3>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="21534e4e55614c4052554453">[email protected]</a> tmp]# cat <<'EOF' > /etc/systemd/system/kubelet.service
|
||
|
||
[Unit]
|
||
|
||
Description=kubelet: The Kubernetes Agent
|
||
|
||
Documentation=http://kubernetes.io/docs/
|
||
[Service]
|
||
|
||
ExecStart=/usr/bin/kubelet
|
||
|
||
Restart=always
|
||
|
||
StartLimitInterval=0
|
||
|
||
RestartSec=10
|
||
[Install]
|
||
|
||
WantedBy=multi-user.target
|
||
|
||
EOF
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7b0914140f3b161a080f1e09">[email protected]</a> tmp]# mkdir -p /etc/systemd/system/kubelet.service.d
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="bcced3d3c8fcd1ddcfc8d9ce">[email protected]</a> tmp]# cat <<'EOF' > /etc/systemd/system/kubelet.service.d/kubeadm.conf
|
||
|
||
[Service]
|
||
|
||
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
|
||
|
||
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
|
||
|
||
EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
|
||
|
||
EnvironmentFile=-/etc/default/kubelet
|
||
|
||
ExecStart=
|
||
|
||
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS
|
||
|
||
EOF
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="582a37372c1835392b2c3d2a">[email protected]</a> tmp]# systemctl enable kubelet
|
||
|
||
Created symlink from /etc/systemd/system/multi-user.target.wants/kubelet.service to /etc/systemd/system/kubelet.service.
|
||
|
||
</code></pre>
|
||
|
||
<p>在这里我们添加了 <code>kubelet</code> 的 systemd 配置,然后添加了它的 <code>Drop-in</code> 文件,我们增加的这个 <code>kubeadm.conf</code> 文件,会被 systemd 自动解析,用于复写 <code>kubelet</code> 的基础 systemd 配置,可以看到我们增加了一系列的配置参数。在第 17 章中,我们会对 <code>kubelet</code> 做详细剖析,到时再进行解释。</p>
|
||
|
||
<h2>启动</h2>
|
||
|
||
<p>此时,我们的前期准备已经基本完成,可以使用 <code>kubeadm</code> 来创建集群了。别着急,在此之前,我们还需要安装两个工具,名为<code>crictl</code> 和 <code>socat</code>。</p>
|
||
|
||
<h3>安装前置依赖 crictl</h3>
|
||
|
||
<p><code>crictl</code> 包含在 <a href="https://github.com/kubernetes-sigs/cri-tools.git"><code>cri-tools</code></a> 项目中,这个项目中包含两个工具:</p>
|
||
|
||
<ul>
|
||
|
||
<li><code>crictl</code> 是 <code>kubelet</code> CRI (Container Runtime Interface) 的 CLI 。</li>
|
||
|
||
<li><code>critest</code> 是 <code>kubelet</code> CRI 的测试工具集。</li>
|
||
|
||
</ul>
|
||
|
||
<p>安装可以通过进入 <code>cri-tools</code> 项目的 <a href="https://github.com/kubernetes-sigs/cri-tools/releases">Release 页面</a> ,根据项目 <a href="https://github.com/kubernetes-sigs/cri-tools#current-status">README</a> 文件中的版本兼容关系,选择自己所需的安装包,下载即可,由于我们安装 K8S 1.11.3 所以选择最新的 v1.11.x 的安装包。</p>
|
||
|
||
<p><img src="assets/1660f7cee66145d1" alt="img" /></p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="9eecf1f1eadef3ffedeafbec">[email protected]</a> ~]# wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.11.1/crictl-v1.11.1-linux-amd64.tar.gz
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2755484853674a4654534255">[email protected]</a> ~]# echo 'ccf83574556793ceb01717dc91c66b70f183c60c2bbec70283939aae8fdef768 crictl-v1.11.1-linux-amd64.tar.gz' | sha256sum -c -
|
||
|
||
crictl-v1.11.1-linux-amd64.tar.gz: 确定
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8cfee3e3f8cce1edfff8e9fe">[email protected]</a> ~]# tar zxvf crictl-v1.11.1-linux-amd64.tar.gz
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d6a4b9b9a296bbb7a5a2b3a4">[email protected]</a> ~]# mv crictl /usr/bin/
|
||
|
||
</code></pre>
|
||
|
||
<h3>安装前置依赖 socat</h3>
|
||
|
||
<p><code>socat</code> 是一款很强大的命令行工具,可以建立两个双向字节流并在其中传输数据。这么说你也许不太理解,简单点说,它其中的一个功能是可以实现端口转发。</p>
|
||
|
||
<p>无论在 K8S 中,还是在 Docker 中,如果我们需要在外部访问服务,端口转发是个必不可少的部分。当然,你可能会问基本上没有任何地方提到说 <code>socat</code> 是一个依赖项啊,别急,我们来看下<a href="https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/dockershim/docker_streaming.go#L189-L192"> K8S 的源码</a>便知道了。</p>
|
||
|
||
<pre><code>func portForward(client libdocker.Interface, podSandboxID string, port int32, stream io.ReadWriteCloser) error {
|
||
|
||
// 省略了和 socat 无关的代码
|
||
socatPath, lookupErr := exec.LookPath("socat")
|
||
|
||
if lookupErr != nil {
|
||
|
||
return fmt.Errorf("unable to do port forwarding: socat not found.")
|
||
|
||
}
|
||
args := []string{"-t", fmt.Sprintf("%d", containerPid), "-n", socatPath, "-", fmt.Sprintf("TCP4:localhost:%d", port)}
|
||
// ...
|
||
|
||
}
|
||
|
||
</code></pre>
|
||
|
||
<p><code>socat</code> 的安装很简单 CentOS 下执行 <code>sudo yum install -y socat</code> ,Debian/Ubuntu 下执行 <code>sudo apt-get install -y socat</code> 即可完成安装。</p>
|
||
|
||
<h3>初始化集群</h3>
|
||
|
||
<p>所有的准备工作已经完成,我们开始真正创建一个 K8S 集群。 <strong>注意:如果需要配置 Pod 网络方案,请先阅读本章最后的部分 配置集群网络</strong></p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fc8e939388bc919d8f88998e">[email protected]</a> ~]# kubeadm init
|
||
|
||
[init] using Kubernetes version: v1.11.3
|
||
|
||
[preflight] running pre-flight checks
|
||
|
||
...
|
||
|
||
I0920 01:09:09.602908 17966 kernel_validator.go:81] Validating kernel version
|
||
|
||
I0920 01:09:09.603001 17966 kernel_validator.go:96] Validating kernel config
|
||
|
||
[WARNING SystemVerification]: docker version is greater than the most recently validated version. Docker version: 18.03.1-ce. Max validated version: 17.03
|
||
|
||
[preflight/images] Pulling images required for setting up a Kubernetes cluster
|
||
|
||
[preflight/images] This might take a minute or two, depending on the speed of your internet connection
|
||
|
||
[preflight/images] You can also perform this action in beforehand using 'kubeadm config images pull'
|
||
|
||
[kubelet] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
|
||
|
||
[kubelet] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
|
||
|
||
[preflight] Activating the kubelet service
|
||
|
||
[certificates] Generated ca certificate and key.
|
||
|
||
[certificates] Generated apiserver certificate and key.
|
||
|
||
...
|
||
|
||
[markmaster] Marking the node master as master by adding the label "node-role.kubernetes.io/master=''"
|
||
|
||
[markmaster] Marking the node master as master by adding the taints [node-role.kubernetes.io/master:NoSchedule]
|
||
|
||
[bootstraptoken] creating the "cluster-info" ConfigMap in the "kube-public" namespace
|
||
|
||
[addons] Applied essential addon: CoreDNS
|
||
|
||
[addons] Applied essential addon: kube-proxy
|
||
Your Kubernetes master has initialized successfully!
|
||
...
|
||
You can now join any number of machines by running the following on each node
|
||
|
||
as root:
|
||
kubeadm join 202.182.112.120:6443 --token t14kzc.vjurhx5k98dpzqdc --discovery-token-ca-cert-hash sha256:d64f7ce1af9f9c0c73d2d737fd0095456ad98a2816cb5527d55f984c8aa8a762
|
||
|
||
</code></pre>
|
||
|
||
<p>以上省略了部分输出。</p>
|
||
|
||
<p>我们从以上日志中可以看到,创建集群时会检查内核版本,Docker 版本等信息,这里提示 Docker 版本较高,我们忽略这个提示。</p>
|
||
|
||
<p>然后会下载一些镜像,当然这里提示我们可以通过执行 <code>kubeadm config images pull</code> 提前去下载镜像。我们来看下</p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="97e5f8f8e3d7faf6e4e3f2e5">[email protected]</a> ~]# kubeadm config images pull
|
||
|
||
[config/images] Pulled k8s.gcr.io/kube-apiserver-amd64:v1.11.3
|
||
|
||
[config/images] Pulled k8s.gcr.io/kube-controller-manager-amd64:v1.11.3
|
||
|
||
[config/images] Pulled k8s.gcr.io/kube-scheduler-amd64:v1.11.3
|
||
|
||
[config/images] Pulled k8s.gcr.io/kube-proxy-amd64:v1.11.3
|
||
|
||
[config/images] Pulled k8s.gcr.io/pause:3.1
|
||
|
||
[config/images] Pulled k8s.gcr.io/etcd-amd64:3.2.18
|
||
|
||
[config/images] Pulled k8s.gcr.io/coredns:1.1.3
|
||
|
||
</code></pre>
|
||
|
||
<p>对于国内用户使用 <code>kubeadm</code> 创建集群时,可能遇到的问题便是这些镜像下载不下来,最终导致创建失败。所以我在国内的代码托管平台提供了一个<a href="https://gitee.com/K8S-release/kubeadm">仓库</a> 可以 clone 该项目,进入 <code>v1.11.3</code> 目录,对每个 <code>tar</code> 文件执行 <code>sudo docker load -i xx.tar</code> 即可将镜像导入。</p>
|
||
|
||
<p>或者可使用<a href="https://dev.aliyun.com/list.html?namePrefix=google-containers">阿里云提供的镜像</a>,只需要将 <code>k8s.gcr.io</code> 替换为 <code>registry.aliyuncs.com/google_containers</code> ,执行 <code>docker pull</code> 后再 <code>docker tag</code> 重 tag 即可。</p>
|
||
|
||
<p>继续看上面的日志,<code>kubeadm init</code> 执行起见生成了一些文件,而这些文件我们先前在 kubelet server 的 <code>Drop-in</code> 的配置中配置过。</p>
|
||
|
||
<p>生成这些配置文件后,将启动 <code>kubelet</code> 服务,生成一系列的证书和相关的配置之类的,并增加一些扩展。</p>
|
||
|
||
<p>最终集群创建成功,并提示可在任意机器上使用指定命令加入集群。</p>
|
||
|
||
<h2>验证</h2>
|
||
|
||
<p>在上面的步骤中,我们已经安装了 K8S 的 CLI 工具 <code>kubectl</code>,我们使用此工具查看集群信息:</p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5f2d30302b1f323e2c2b3a2d">[email protected]</a> ~]# kubectl cluster-info
|
||
|
||
Kubernetes master is running at http://localhost:8080
|
||
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
|
||
|
||
The connection to the server localhost:8080 was refused - did you specify the right host or port?
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2e5c41415a6e434f5d5a4b5c">[email protected]</a> ~]# kubectl get nodes
|
||
|
||
The connection to the server localhost:8080 was refused - did you specify the right host or port?
|
||
|
||
</code></pre>
|
||
|
||
<p>使用 <code>kubectl cluster-info</code> 可查看集群 master 和集群服务的地址,但我们也注意到最后有一句报错 <code>connection ... refused</code> 很显然这里存在错误。</p>
|
||
|
||
<p><code>kubectl get nodes</code> 可查看集群中 <code>Node</code> 信息,同样报错。</p>
|
||
|
||
<p>在上面我们提到过,K8S 默认会监听一些端口,但并不是 <code>8080</code> 端口,由此可知,我们的 <code>kubectl</code> 配置有误。</p>
|
||
|
||
<h3>配置 kubectl</h3>
|
||
|
||
<ul>
|
||
|
||
<li>
|
||
|
||
<p>使用 <code>kubectl</code> 的参数 <code>--kubeconfig</code> 或者环境变量 <code>KUBECONFIG</code> 。</p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="1f6d70706b5f727e6c6b7a6d">[email protected]</a> ~]# kubectl --kubeconfig /etc/kubernetes/admin.conf get nodes
|
||
|
||
NAME STATUS ROLES AGE VERSION
|
||
|
||
master NotReady master 13h v1.11.3
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5624393922163b3725223324">[email protected]</a> ~]#
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="64160b0b1024090517100116">[email protected]</a> ~]# KUBECONFIG=/etc/kubernetes/admin.conf kubectl get nodes
|
||
|
||
NAME STATUS ROLES AGE VERSION
|
||
|
||
master NotReady master 13h v1.11.3
|
||
|
||
</code></pre>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>使用传参的方式未免太繁琐,我们也可以更改默认配置文件</p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3a4855554e7a575b494e5f48">[email protected]</a> ~]# mkdir -p $HOME/.kube
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="cdbfa2a2b98da0acbeb9a8bf">[email protected]</a> ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f1839e9e85b19c9082859483">[email protected]</a> ~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="87f5e8e8f3c7eae6f4f3e2f5">[email protected]</a> ~]# kubectl get nodes
|
||
|
||
NAME STATUS ROLES AGE VERSION
|
||
|
||
master NotReady master 13h v1.11.3
|
||
|
||
</code></pre>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
<h3>配置集群网络</h3>
|
||
|
||
<p>通过上面的配置,我们已经可以正常获取 <code>Node</code> 信息。但通过第 2 章,我们了解到 <code>Node</code> 都有 <code>status</code>,而此时我们唯一的 <code>Node</code> 是 <code>NotReady</code>。我们通过给 <code>kubectl</code> 传递 <code>-o</code> 参数更改输出格式,查看更详细的情况。</p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="80f2efeff4c0ede1f3f4e5f2">[email protected]</a> ~]# kubectl get nodes -o yaml
|
||
|
||
apiVersion: v1
|
||
|
||
items:
|
||
|
||
- apiVersion: v1
|
||
|
||
kind: Node
|
||
|
||
...
|
||
|
||
status:
|
||
|
||
addresses:
|
||
|
||
- address: master
|
||
|
||
type: Hostname
|
||
|
||
...
|
||
|
||
- lastHeartbeatTime: 2018-09-20T14:45:45Z
|
||
|
||
lastTransitionTime: 2018-09-20T01:09:48Z
|
||
|
||
message: 'runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady
|
||
|
||
message:docker: network plugin is not ready: cni config uninitialized'
|
||
|
||
reason: KubeletNotReady
|
||
|
||
status: "False"
|
||
|
||
type: Ready
|
||
|
||
...
|
||
|
||
</code></pre>
|
||
|
||
<p>从以上输出中,我们可以看到 master 处于 <code>NotReady</code> 的原因是 <code>network plugin is not ready: cni config uninitialized</code> 那么 <code>CNI</code> 是什么呢?<code>CNI</code> 是 Container Network Interface 的缩写,是 K8S 用于配置 Linux 容器网络的接口规范。</p>
|
||
|
||
<p>关于网络的选择,我们此处不做过多介绍,我们暂时选择一个被广泛使用的方案 <code>flannel</code>。 但注意,如果要使用 <code>flannel</code> 需要在 <code>kubeadm init</code> 的时候,传递 <code>--pod-network-cidr=10.244.0.0/16</code> 参数。另外需要查看 <code>/proc/sys/net/bridge/bridge-nf-call-iptables</code> 是否已设置为 <code>1</code>。 可以通过 <code>sysctl net.bridge.bridge-nf-call-iptables=1</code> 更改配置。</p>
|
||
|
||
<p>我们在前面创建集群时,并没有传递任何参数。为了能使用 <code>flannel</code> , 所以我们需要先将集群重置。使用 <code>kubeadm reset</code></p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="dba9b4b4af9bb6baa8afbea9">[email protected]</a> ~]# kubeadm reset
|
||
|
||
[reset] WARNING: changes made to this host by 'kubeadm init' or 'kubeadm join' will be reverted.
|
||
|
||
[reset] are you sure you want to proceed? [y/N]: y
|
||
|
||
[preflight] running pre-flight checks
|
||
|
||
[reset] stopping the kubelet service
|
||
|
||
[reset] unmounting mounted directories in "/var/lib/kubelet"
|
||
|
||
[reset] removing kubernetes-managed containers
|
||
|
||
[reset] cleaning up running containers using crictl with socket /var/run/dockershim.sock
|
||
|
||
[reset] failed to list running pods using crictl: exit status 1. Trying to use docker instead[reset] deleting contents of stateful directories: [/var/lib/kubelet /etc/cni/net.d /var/lib/dockershim /var/run/kubernetes /var/lib/etcd]
|
||
|
||
[reset] deleting contents of config directories: [/etc/kubernetes/manifests /etc/kubernetes/pki]
|
||
|
||
[reset] deleting files: [/etc/kubernetes/admin.conf /etc/kubernetes/kubelet.conf /etc/kubernetes/bootstrap-kubelet.conf /etc/kubernetes/controller-manager.conf /etc/kubernetes/scheduler.conf]
|
||
|
||
</code></pre>
|
||
|
||
<p>重新初始化集群,并传递参数。</p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e89a87879ca885899b9c8d9a">[email protected]</a> ~]# kubeadm init --pod-network-cidr=10.244.0.0/16
|
||
|
||
[init] using Kubernetes version: v1.11.3
|
||
|
||
...
|
||
|
||
Your Kubernetes master has initialized successfully!
|
||
|
||
</code></pre>
|
||
|
||
<p><strong>注意:这里会重新生成相应证书等配置,需要按上面的内容重新配置 kubectl。</strong></p>
|
||
|
||
<p>此时,<code>CNI</code> 也尚未初始化完成,我们还需完成以下的步骤。</p>
|
||
|
||
<pre><code># 注意,这里的 flannel 配置仅适用于 1.11 版本的 K8S,若安装其他版本的 K8S 需要替换掉此链接
|
||
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="89fbe6e6fdc9e4e8fafdecfb">[email protected]</a> ~]# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.10.0/Documentation/kube-flannel.yml
|
||
|
||
clusterrole.rbac.authorization.k8s.io/flannel created
|
||
|
||
clusterrolebinding.rbac.authorization.k8s.io/flannel created
|
||
|
||
serviceaccount/flannel created
|
||
|
||
configmap/kube-flannel-cfg created
|
||
|
||
daemonset.extensions/kube-flannel-ds created
|
||
|
||
</code></pre>
|
||
|
||
<p>稍等片刻,再次查看 Node 状态:</p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2755484853674a4654534255">[email protected]</a> ~]# kubectl get nodes
|
||
|
||
NAME STATUS ROLES AGE VERSION
|
||
|
||
master Ready master 12m v1.11.3
|
||
|
||
</code></pre>
|
||
|
||
<p>可以看到 status 已经是 <code>Ready</code> 状态。根据第 3 章的内容,我们知道 K8S 中最小的调度单元是 <code>Pod</code> 我们来看下集群中现有 <code>Pod</code> 的状态。</p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a1d3ceced5e1ccc0d2d5c4d3">[email protected]</a> ~]# kubectl get pods --all-namespaces
|
||
|
||
NAMESPACE NAME READY STATUS RESTARTS AGE
|
||
|
||
kube-system coredns-78fcdf6894-h7pkc 0/1 ContainerCreating 0 12m
|
||
|
||
kube-system coredns-78fcdf6894-lhlks 0/1 ContainerCreating 0 12m
|
||
|
||
kube-system etcd-master 1/1 Running 0 5m
|
||
|
||
kube-system kube-apiserver-master 1/1 Running 0 5m
|
||
|
||
kube-system kube-controller-manager-master 1/1 Running 0 5m
|
||
|
||
kube-system kube-flannel-ds-tqvck 1/1 Running 0 6m
|
||
|
||
kube-system kube-proxy-25tk2 1/1 Running 0 12m
|
||
|
||
kube-system kube-scheduler-master 1/1 Running 0 5m
|
||
|
||
</code></pre>
|
||
|
||
<p>我们发现有两个 <code>coredns</code> 的 <code>Pod</code> 是 <code>ContainerCreating</code> 的状态,但并未就绪。根据第 3 章的内容,我们知道 <code>Pod</code> 实际会有一个调度过程,此处我们暂且不论,后续章节再对此进行解释。</p>
|
||
|
||
<h3>新增 Node</h3>
|
||
|
||
<p>我们按照刚才执行完 <code>kubeadm init</code> 后,给出的信息,在新的机器上执行 <code>kubeadm join</code> 命令。</p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e5978a8a91a58b8a8180d4">[email protected]</a> ~]# kubeadm join 202.182.112.120:6443 --token t14kzc.vjurhx5k98dpzqdc --discovery-token-ca-cert-hash sha256:d64f7ce1af9f9c0c73d2d737fd0095456ad98a2816cb5527d55f984c8aa8a762
|
||
|
||
[preflight] running pre-flight checks
|
||
|
||
[WARNING RequiredIPVSKernelModulesAvailable]: the IPVS proxier will not be used, because the following required kernel modules are not loaded: [ip_vs ip_vs_rr ip_vs_wrr ip_vs_sh] or no builtin kernel ipvs support: map[ip_vs:{} ip_vs_rr:{} ip_vs_wrr:{} ip_vs_sh:{} nf_conntrack_ipv4:{}]
|
||
|
||
you can solve this problem with following methods:
|
||
|
||
1. Run 'modprobe -- ' to load missing kernel modules;
|
||
|
||
2. Provide the missing builtin kernel ipvs support
|
||
I0921 04:00:54.805439 10677 kernel_validator.go:81] Validating kernel version
|
||
|
||
I0921 04:00:54.805604 10677 kernel_validator.go:96] Validating kernel config
|
||
|
||
[WARNING SystemVerification]: docker version is greater than the most recently validated version. Docker version: 18.03.1-ce. Max validated version: 17.03
|
||
|
||
[discovery] Trying to connect to API Server "202.182.112.120:6443"
|
||
|
||
[discovery] Created cluster-info discovery client, requesting info from "https://202.182.112.120:6443"
|
||
|
||
[discovery] Requesting info from "https://202.182.112.120:6443" again to validate TLS against the pinned public key
|
||
|
||
[discovery] Cluster info signature and contents are valid and TLS certificate validates against pinned roots, will use API Server "202.182.112.120:6443"
|
||
|
||
[discovery] Successfully established connection with API Server "202.182.112.120:6443"
|
||
|
||
[kubelet] Downloading configuration for the kubelet from the "kubelet-config-1.11" ConfigMap in the kube-system namespace
|
||
|
||
[kubelet] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
|
||
|
||
[kubelet] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
|
||
|
||
[preflight] Activating the kubelet service
|
||
|
||
[tlsbootstrap] Waiting for the kubelet to perform the TLS Bootstrap...
|
||
|
||
[patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "node1" as an annotation
|
||
This node has joined the cluster:
|
||
|
||
* Certificate signing request was sent to master and a response
|
||
|
||
was received.
|
||
|
||
* The Kubelet was informed of the new secure connection details.
|
||
Run 'kubectl get nodes' on the master to see this node join the cluster.
|
||
|
||
</code></pre>
|
||
|
||
<p>上面的命令执行完成,提示已经成功加入集群。 此时,我们在 master 上查看下当前集群状态。</p>
|
||
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4b3924243f0b262a383f2e39">[email protected]</a> ~]# kubectl get nodes
|
||
|
||
NAME STATUS ROLES AGE VERSION
|
||
|
||
master Ready master 12m v1.11.3
|
||
|
||
node1 Ready <none> 7m v1.11.3
|
||
|
||
</code></pre>
|
||
|
||
<p>可以看到 node1 已经加入了集群。</p>
|
||
|
||
<h2>总结</h2>
|
||
|
||
<p>在本节中,我们选择官方推荐的 <code>kubeadm</code> 工具在服务器上搭建了一套有两个节点的集群。</p>
|
||
|
||
<p><code>kubeadm</code> 可以自动的拉取相关组件的 Docker 镜像,并将其“组织”起来,免去了我们逐个部署相关组件的麻烦。</p>
|
||
|
||
<p>我们首先学习到了部署 K8S 时需要对系统做的基础配置,其次安装了一些必要的工具,以便 K8S 的功能可正常运行。</p>
|
||
|
||
<p>其次,我们学习到了 CNI 相关的知识,并在集群中部署了 <code>flannel</code> 网络方案。</p>
|
||
|
||
<p>最后,我们学习了增加 Node 的方法,以便后续扩展集群。</p>
|
||
|
||
<p>集群搭建方面的学习暂时告一段落,但这并不是结束,这才是真正的开始,从下一章开始,我们要学习集群管理相关的内容,学习如何真正使用 K8S 。</p>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div>
|
||
|
||
<div style="float: left">
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/04 搭建 Kubernetes 集群 - 本地快速搭建.md.html">上一页</a>
|
||
|
||
</div>
|
||
|
||
<div style="float: right">
|
||
|
||
<a href="/专栏/Kubernetes 从上手到实践/06 集群管理:初识 kubectl.md.html">下一页</a>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||
|
||
</div>
|
||
|
||
<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script><script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70997234aa723d60","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
|
||
|
||
</body>
|
||
|
||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||
|
||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
|
||
|
||
<script>
|
||
|
||
window.dataLayer = window.dataLayer || [];
|
||
function gtag() {
|
||
|
||
dataLayer.push(arguments);
|
||
|
||
}
|
||
gtag('js', new Date());
|
||
|
||
gtag('config', 'G-NPSEEVD756');
|
||
|
||
var path = window.location.pathname
|
||
|
||
var cookie = getCookie("lastPath");
|
||
|
||
console.log(path)
|
||
|
||
if (path.replace("/", "") === "") {
|
||
|
||
if (cookie.replace("/", "") !== "") {
|
||
|
||
console.log(cookie)
|
||
|
||
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
setCookie("lastPath", path)
|
||
|
||
}
|
||
function setCookie(cname, cvalue) {
|
||
|
||
var d = new Date();
|
||
|
||
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
|
||
|
||
var expires = "expires=" + d.toGMTString();
|
||
|
||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||
|
||
}
|
||
function getCookie(cname) {
|
||
|
||
var name = cname + "=";
|
||
|
||
var ca = document.cookie.split(';');
|
||
|
||
for (var i = 0; i < ca.length; i++) {
|
||
|
||
var c = ca[i].trim();
|
||
|
||
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
|
||
|
||
}
|
||
|
||
return "";
|
||
|
||
}
|
||
</script>
|
||
</html>
|
||
|