容器、Docker与Kubernetes——Kubernetes的配置入门

本文讲的是容器、Docker与Kubernetes——Kubernetes的配置入门【编者的话】这是介绍Kubernetes的第三篇,主要集中讲述如何配置Kubernetes集群以及作者在配置过程中遇到的问题。

【3 天烧脑式容器存储网络训练营 | 深圳站】本次培训以容器存储和网络为主题,包括:Docker Plugin、Docker storage driver、Docker Volume Pulgin、Kubernetes Storage机制、容器网络实现原理和模型、Docker网络实现、网络插件、Calico、Contiv Netplugin、开源企业级镜像仓库Harbor原理及实现等。

在本系列文章的第一部分中,我们探讨了容器、Docker以及这些技术如何重新定义行业中的基础设施及其运营方式。第二部分文章则继续讨论,着眼点放在Kubernetes身上——包括Kubernetes是什么以及拥有哪些能力。在今天的第三部分文章中,我将进一步阐述如何上手Kubernetes,同时提供与结构设计相关的一点参考意见。

命令(Command)

Kubernetes的集群管理是通过kubectl命令进行的,如果你使用Google Cloud,则会在SDK中自动安装kubectl命令行工具。虽然你可以完全使用这个命令行工具来配置、控制Kubernetes集群,但是我还是十分推荐你使用单独的配置文件来配置集群,因为你可以使用版本控制工具来追踪每次对集群配置的修改而且保证配置的统一,后面会着重介绍如何去做。

kubectl命令集合包含了非常多的子命令来帮助你控制Kubernetes集群的方方面面,如窥探当前集群的工作状态等等。下面是我觉得非常常用的几个命令,并将其分类说明。

管理类(Management)

kubectl apply -f service-file.yml

apply命令会收集配置文件(service-file.yml)中所有的配置项信息,并自动将配置文件中的配置项跟当前集群的运行配置做对比,然后自动将必要的更新应用到当前集群中。

kubectl rollout

所有通过apply命令触发的指令都会生成一个新的Rollout对象。通过使用kubectl rollout status命令可以查看最近的更新状态、终止一个rollout或者回滚到上一个资源对象(Deployment,Pod,Service等)的版本。

窥探类(Introspection)

kubectl describe [pod,service,...] [resource]

这条命令可以查看某个资源的详细信息,当错误发生的时候你必须首选考虑使用describe命令来获取错误描述信息。

kubectl logs [resource]

Kubernetes内的容器会倾向于把所有的日志定向到STDOUT上,kubectl logs -f命令能让你获取一个资源(Pod/Container)最新的日志。

kubectl get [pods,deployments,services,...]

这条命令会将Kubernetes默认命名空间中运行的资源信息打印出来,如果要看特定命名空间的资源信息,则必须加上--namespace=[my namespace]参数,如果查看所有命名空间的资源信息,则使用--all-namespace参数。

kubectl exec

这条命令是对docker exec命令的包装,可以让你执行容器内部的命令,如果pod中只有一个容器在运行则此命令可以作用在pod上如:kubectl exec -it [pod] /bin/bash。我们可以使用kubectl exec -it [pod name] --/bin/bash来进入一个运行中的pod,-i用来启动标准输入流STDIN-t将输入流定向到TTY(伪终端)中,这样就能模拟终端的bash命令操作了。当然如果一个Pod中启动了多个容器,你可以使用-C[container-name]参数来进入特定的容器中。

部署新镜像

当前还没有命令能够让一个Deployment自动将配置的Pod下的容器更新到最新的版本;但是为Kubernetes集群更新容器版本又是一个非常常见的操作,这时你就必须想清楚更新容器的步骤了,我列出以下几种方法:

  • 将新的容器打上:latest的Tag,然后手动删除运行中的Pod,然后Deployment会自动用最新的容器重新启动Pod;
  • 更新服务的配置文件(Deployment yaml),让容器指向指向最新的container label,比如:redis-cache:9c713a,然后重新apply这个配置文件到Kubernetes的集群中,这种方式需要对配置文件进行版本控制;
  • 手动更新Deployment下Pod的镜像版本:kubectl set image deployment/[service name] *=[new image]

我需要的方案是即能够在Kubernetes中留下更改历史,也不想因为老是去提交配置文件的更改导致陷入版本混乱的泥沼。所以,我个人选择第三种方案,我是这么操作的:

  • 所有Pod template的image都指向容器的:latest tag;
  • 新的容器被Push到注册中心时除了打上:latest tag以外还要打上与代码git仓库HEAD指针指向的Commit号相同的tag(如:9c713a);
  • 运行kubectl set image deployment/[service name] *=[new image] 时填入git commit hash号标识的镜像。

根据以上几点,我可以获得一些好处:

  1. set image 命令来更新Pods的镜像非常的优雅,因为可以使用kubectl rollout status来跟踪所有Deployment的Pods的更新状态;
  2. 当Pod因为某些原因被杀掉或者新的Pod上线,都会确保运行拥有最新代码的镜像;
  3. 我可以在minikube中使用跟Kubernetes集群中相同的docker registry而不用担心会影响到生产环境的Pods;我一直到上线前都不会使用:latest tag的镜像(注:在测试环境或者非生产环境使用git commit hash号来启动容器,但是在生产时使用:latest,因为作者在push镜像时同时打了两个tag)。

搭建本地开发环境

Kubernetes开发人员不仅提供了相当全面的文档可以参考,而且提供了minikube这个可以让开发者在本地环境运行Kubernetes集群的工具。minikube可以运行在多种不同的虚拟化环境下,它可以很容易的启动一个全功能的,包含一个单一节点的Kubernetes集群。当集群启动后,minikube提供了多种命令来访问与窥探集群运行情况,同时kubectl工具也是自动为minikube配置好的。最常用的命令莫过于:

minikube service [service name] --url

这条命令能够打印出本地集群中配好的Service的访问url地址。

minikube dashboard

这会跳转到一个web-based的集群看板页面,帮助你通过可视化的方式了解集群运行的状况。

同时我建议将运行minikube的默认的VM配置加高一点,比如配置:4CPUs与8GB内存,使用VMWare Fusion作为VM容器,例如可以使用如下命令:

minikube config set cpus 4
minikube config set memory 8192
minikube start --vm-driver vmwarefusion

如果要让kubectl退出对minikube的访问,必须重新配置kubectl让它连接到新的集群;如下命令:

kubectl config get-contexts
kubectl config use-context [cluster context name from above] 

当然,如果要重新连接到本地的minikube,只需要使用这条命令:

kubectl config use-context minikube

Service的配置

Service的配置文件支持JSONYAML,但是我推荐使用YAML,因为它比较容易读写,而且支持注释,这对那些复杂的结构非常管用。

对于集群的配置,Service往往是最先配置的,这就是所谓的Service-first配置法。具体的做法是,为每个要创建的服务分配一个单独的文件夹,这个文件夹中包含了所有启动这个服务的配置文件。为了搜索方面,我建议为每个Kubernetes的Service资源创建一个yaml配置文件,可以这样命名:[service name]-k8s.yml,这个配置文件中写入所有这个Service在Kubernetes环境启动的配置项。

如下是我配置一个Redis缓存服务的目录结构:

services/
redis-cache/
        Dockerfile
        redis.conf
        redis-cache-k8s.yml

以下是服务配置文件redis-cache-k8s.yml:

apiVersion: v1
kind: Service
metadata:
name: redis-cache
labels:
role: cache
spec:
type: NodePort
ports:
- port: 6379
targetPort: 6379
selector:
role: cache

---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-cache
spec:
# https://github.com/kubernetes/kubernetes/issues/23597
revisionHistoryLimit: 3
replicas: 1
template:
metadata:
  labels:
    role: cache
spec:
  containers:
  - name: redis
    image: redis:3
    resources:
      requests:
        cpu: 100m
        memory: 1Gi
    ports:
      - containerPort: 6379

然后通过运行apply -f service/redis-cache/redis-cache-k8s.yml 命令就能让redis-cache服务在整个Deployment中跑起来。

容器与注册中心

如何为容器打Tag

我现在为每个容器都打两个tag分别是::latest与对应代码git库中的HEAD指针Commit的hash值如::9c713a。很多人强烈推荐不要使用:latest tag,原因在这里(注:内容大概讲docker registry并不会主动判断一个镜像是否是最新的,而是可以人为的随意为一个老的镜像打上latest tag的,所以很多人认为latest标签的镜像其实并不一定是最新的),但是我觉得这些都是讲给那些只用latest标签的人听的。我为什么这么做的原因在上面“部署新镜像”一节已经阐述。

确保Minikube能访问GKE的Registry

我早期使用minikube遇到的问题是如何让我的Pod有权限从我的Google私有镜像仓库中拉取docker镜像。当然,当我在GKE中使用Kubernetes集群拉取镜像是没有问题的,因为当使用GKE时,所有的服务器都自动被赋予了访问Google私有镜像仓库的的权限,但是作为本地运行的minikube就没有权限了。

解决方法是在Pod的spec节中使用imagePullSecrets值。首先,登录Google Cloud,然后前往IAM并创建一个新的Service Account 并赋予Storage -> Storage Object Viewer权限,确保勾选“Furnish a new private key”选项,完事后会给你一个JSON文件,这个文件你需要本地保存,是用于授权的;所有这些准备就绪后运行这段脚本生成一个新的Secret资源:

#!/usr/bin/env sh

SPATH="$(cd $(dirname "$0") && pwd -P)"
SECRET_NAME=${1:-docker-registry-secret}
CONFIG_PATH=${2:-$SPATH/localkube.json}
if [[ ! -f $CONFIG_PATH ]]; then
echo "Unable to locate service account config JSON: $CONFIG_PATH";
exit 1;
fi

kubectl create secret docker-registry $SECRET_NAME  \
--docker-server "https://gcr.io" \
--docker-username _json_key \
--docker-email [service account email address] \
--docker-password="`cat $CONFIG_PATH`" ${@:3} 

这段脚本会生成一个名为docker-registry-secret的Secret资源,这个资源稍后要在Service的配置文件中的imagePullSecrets 值中被引用,如下所示:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-cache
spec:
...
template:
spec:
  imagePullSecrets:
  - name: docker-registry-secret
  ...
  containers:
  - name: redis
    image: gcr.io/[google account id]/redis-cache:latest
...

配置完成后应该就能从Google私有镜像仓库中拉取镜像了。

Secrets资源

敏感的数据比如:密码,认证码与各种key,这些都是要做特殊处理并很容易出错的数据。首先,如果将这些数据不加密的保存在代码管理仓库中,不管这个仓库多么机密,并不是一个保险的做法;但同时,你又必须把这些数据加密并保存在某个安全的地方,并使用一个跟踪系统对其做版本记录与权限控制。我使用了很多不同的加密、保存方式,发现StackExchange的BlackBox非常好用。

BlackBox使用PGP/GPG(非对称加密)加密方式对文件进行加密,确保只有特定的用户才能访问加密的文件。对一个用户授权访问某个资源只需这个用户提供自己的GPG公钥,而移除一个用户的授权只需要在一些配置文件中将其名字去掉即可;然后你要做的事就是告诉BlackBox哪些文件需要加密,而其余的工作交给BlackBox即可,被加密的配置文件可以放心的放入git仓库了。

将这些加密的信息提供给Kubernetes需要一些额外的本地脚本,因为Kubernetes将配置信息以明文的方式存储在etcd中。比如:我会对两类文件进行加密:1、YAML配置文件,内部包含很多key-value形式保存的敏感信息(如:数据库密码等);2、一些公钥文件如:SSL Certificate或者其他秘钥。然后,我使用rake来解密这些文件,然后将解密的文件应用到Kubernetes集群中,使用命令:apply -f -(注意:'-'表示STDIN)。

比如,我有个加密的YAML文件,如下:

---
rails:
secret_key_base: "..."
service_api_key: "..."
database:
username: "..."
password: "..."

然后导入Kubernetes的Secret:

raw_secrets = `blackbox_cat secrets/my-secrets.yml.gpg`

secrets = YAML.load(raw_secrets)

secrets.each do |name, values|
k8s_secret = {
"apiVersion" => "v1",
"kind" => "Secret",
"type" => "Opaque",
"metadata" => { "name" => name },
"data" => {},
}

values.each do |key, value|
k8s_secret["data"][key] = Base64.strict_encode64(value)
end

stdout, status = Open3.capture2("kubectl apply -f -", stdin_data: k8s_secret.to_yaml)
end 

然后在Service的配置文件中来引用这些Secret(使用Secret名称,我通常使用环境变量来指定):

...
env:
- name: RAILS_SECRET_KEY_BASE
valueFrom:
  secretKeyRef:
    name: rails
    key: secret_key_base
- name: RAILS_SERVICE_API_KEY
valueFrom:
  secretKeyRef:
    name: rails
    key: service_api_key
- name: DATABASE_USERNAME
valueFrom:
  secretKeyRef:
    name: database
    key: username
- name: DATABASE_PASSWORD
valueFrom:
  secretKeyRef:
    name: database
    key: password

我认为这是我使用、配置Kubernetes过程中遇到的主要问题,希望对您有帮助。

原文链接:CONTAINERS, DOCKER, AND KUBERNETES PART 3(翻译:肖劲)

原文发布时间为:2017-07-07

本文作者:肖劲

本文来自合作伙伴Dockerone.io,了解相关信息可以关注Dockerone.io。

原文标题:容器、Docker与Kubernetes——Kubernetes的配置入门

时间: 2024-09-15 14:16:19

容器、Docker与Kubernetes——Kubernetes的配置入门的相关文章

开源容器集群管理系统Kubernetes架构及组件介绍

Together we will ensure that Kubernetes is a strong and open container management framework for any application and in any environment, whether in a private, public or hybrid cloud. --Urs Hölzle, Google Kubernetes 作为Docker生态圈中重要一员,是Google多年大规模容器管理技术的

Docker Swarm和Kubernetes在大规模集群中的性能比较

本文讲的是Docker Swarm和Kubernetes在大规模集群中的性能比较,[编者的话]本文建立了一套通用测评工具,通过容器启动时延等指标测评Swarm和Kubernetes在大规模部署下的性能表现,分析结果认为Swarm比Kubernetes的性能好.此外还提供了详尽的测试数据, 供应用者参考. 这篇文章主要针对Docker Swarm和Kubernetes在大规模部署的条件下的3个问题展开讨论.在大规模部署下,它们的性能如何?它们是否可以被批量操作?需要采取何种措施来支持他们的大规模部

Docker Swarm vs Kubernetes

本文讲的是Docker Swarm vs Kubernetes[编者的话]文章介绍了Docker Swarm和Kubernetes间的不同,以及优缺点. [3 天烧脑式容器存储网络训练营 | 深圳站]本次培训以容器存储和网络为主题,包括:Docker Plugin.Docker storage driver.Docker Volume Pulgin.Kubernetes Storage机制.容器网络实现原理和模型.Docker网络实现.网络插件.Calico.Contiv Netplugin.开

编排管理成容器云关键,Kubernetes和Swarm该选谁

  不论是公有云还是私有云环境,Docker 在新一代技术架构中的重要地位已经毋庸多言,甚至已经有企业在探索完全 Docker 化.在此背景下,如何选择容器技术栈就成为了企业实践的关键.回答这个问题,首先需要厘清技术体系更新的逻辑,再看可选技术是否符合需求.本文认为,容器的管理和编排将是容器云的关键,而 Kubernetes 是最为成熟的编排技术. 容器管理和编排将成云计算主战场 从云化的诱因说起.中国云计算实践八年多,市场认知逐渐提升,锐意创新企业对云的期待已经不是资源弹性.成本优势那么简单,

阿里云容器服务-高可用Kubernetes部署指南

Kubernetes是非常流行的容器管控技术,为了让Kubernetes可以更深度集成阿里云的计算.存储和网络服务,以提供更佳的性能和网络特性支持,阿里云容器服务团队为Kubernetes提供了基于阿里云服务的CloudProvider插件. 同时,基于阿里云资源编排服务ROS的应用部署能力,阿里云用户可以非常方便的快速部署Kubernetes集群.本文接下来会详细介绍部署过程. 依赖条件 需要事先开通访问控制RAM服务,访问https://ram.console.aliyun.com点击开通服

为什么微软应该通过收购Docker来与Kubernetes竞争

前言 Docker自今年4月Dockercon以来,都在对外宣称一件事:Docker已正式布局企业级服务,要利用已有的资源实现自身盈利需求.虽然Docker自有其扩展的优势,但从市场的另一端来看,Google在这方面则表现更强势.Kubernetes有Google的强大靠山,而Docker也不会孤军奋战,目前看来,Docker和微软的结合有可能给容器市场带来更多活力:Docker需要盈利,微软则需要Docker来与Google竞争. 目前看来,Kubnernetes的胜利姿态最终傲视了容器编排这

docker(3):配置rancher网络环境,下载启动tomcat容器

1,关于rancher 上次搭建好了rancher的环境但是网络啥的没有配置好. 没有成功创建容器.这次搞定了,原来是网络的问题. 之前virtualbox安装的coreos没有配置ip,造成网络访问不到. agent没有注册成功,没有主机环境,创建不了docker应用 . 2,配置网络 如果没有配置virtualbox的网络环境的时候,网络是nat的环境,这个时候只要将主见设置成 10.0.2.15 即可. 这个是virtualbox分配的nat的ip,但是这个网络是不能和外接通讯的. 只能使

Structs中基本配置入门

  1.为Structs应用配置Web.xml文件 第一步:配置ActionServlet   <servlet> <servlet-name>action</servlet-name> <servlet-class>org.appache. structs.ActionSer vlet</servlet-class></servlet><servlet-mapping> <servlet-name>actio

将Node.js项目docker容器化并纳入kubernetes调度编排的实践

  简述 此文档以XXXLogApi-nj项目为例,讲解了将基于Node.js+Express开发的javascript项目容器化的过程.希望以后类似的项目可以以此为参照进行扩展. XXXLogApi-nj本身是一个微服务化的项目,其作用是为系统单纯的收集相关发布日志,以便能及时的展示给用户. ***这份文档的操作,开始于编码完成之后流程.不涉及GIT和JENKINS的等的操作. ***为保持职业操作,涉及公司信息的地方作了敏感化处理. ***在这个系列中,我同时作了spring boot, b