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

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 本文讲的是容器、Docker与Kubernetes——Kubernetes的配置入门【编者的话】这是介绍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的配置文件支持 JSON YAML ,但是我推荐使用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的配置入门

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
1天前
|
Ubuntu Linux 测试技术
Linux(32)Rockchip RK3568 Ubuntu22.04上部署 Docker: 详细配置与功能测试(下)
Linux(32)Rockchip RK3568 Ubuntu22.04上部署 Docker: 详细配置与功能测试
19 1
|
6天前
|
存储 运维 监控
构建高效稳定的Docker容器监控体系
【4月更文挑战第18天】 在现代微服务架构中,Docker容器已成为部署和运行应用的标准环境。随之而来的挑战是如何有效监控这些容器的性能与健康状况,确保系统的稳定性和可靠性。本文将探讨构建一个高效稳定的Docker容器监控体系的关键技术和方法,包括日志管理、性能指标收集以及异常检测机制,旨在为运维人员提供实用的指导和建议。
11 0
|
8天前
|
程序员 索引 Python
06-python数据容器-set(集合)入门基础操作
06-python数据容器-set(集合)入门基础操作
|
12天前
|
JSON Kubernetes Go
无缝集成:在IntelliJ IDEA中利用Kubernetes插件轻松管理容器化应用
无缝集成:在IntelliJ IDEA中利用Kubernetes插件轻松管理容器化应用
22 0
无缝集成:在IntelliJ IDEA中利用Kubernetes插件轻松管理容器化应用
|
15天前
|
Linux Docker 容器
docker 容器常用命令
docker 容器常用命令
13 0
|
15天前
|
Linux Shell 虚拟化
linux 部署docker容器虚拟化平台(二)--------docker 镜像制作方法
linux 部署docker容器虚拟化平台(二)--------docker 镜像制作方法
26 0
|
15天前
|
存储 Linux Shell
centos 部署docker容器 安装 、基本使用方法(一)
centos 部署docker容器 安装 、基本使用方法(一)
27 0
|
18天前
|
Ubuntu 网络安全 数据安全/隐私保护
ubuntu篇-配置FTP服务,本机和docker安装
通过以上步骤,你可以在Ubuntu上配置FTP服务,无论是本机安装还是Docker内安装,都可以提供FTP文件传输服务。 买CN2云服务器,免备案服务器,高防服务器,就选蓝易云。百度搜索:蓝易云
20 1
|
1月前
|
Java Go 开发者
Docker容器技术简介及其与Go语言的结合点
【2月更文挑战第23天】本文首先概述了Docker容器技术的核心概念和优势,接着探讨了Go语言与Docker容器技术的结合点。通过阐述Docker的轻量级、可移植性和版本控制等特性,以及Go语言在容器化应用中的优势,本文旨在说明两者结合能够实现更高效、灵活的应用开发和部署。
|
1月前
|
Oracle 关系型数据库 数据库

相关产品

  • 容器服务Kubernetes版