前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >待补充说明

待补充说明

作者头像
全栈工程师修炼指南
发布2022-09-29 19:34:54
7350
发布2022-09-29 19:34:54
举报

[TOC]

runAsUser

Pod中的,runAsUser 能指定 Pod 中的所有容器内的进程都使用用户 ID runAsUser 来运行。而如果容器中也设置了runAsUser则以容器中设置的优先,服务启动将以runAsUser设置的用户ID运行。 runAsGroup

Pod中的,runAsGroup 能指定 Pod 中的所有容器内的进程都使用用户 ID runAsGroup 来运行。而如果容器中也设置了runAsGroup则以容器中设置的优先,服务启动将以runAsGroup设置的用户ID运行。 fsGroup

fsGroup 会设置挂载文件的访问权限,并且容器中所有进程也会是附组 ID fsGroup privileged

privileged 为特权运行模式,当设置后容器中将有与内核交互的权限,譬如通过proc系统配置系统最大可打开文件数(设置/proc/sys/fs/file-max 文件),或者改变协议栈的tcp握手行为。 RunAsNonRoot

当RunAsNonRoot 为true不允许用户以任何方式(譬如sudo)使用root用户运行服务。

DIND(Docker-in-Docker)是让你可以在 Docker 容器里面运行 Docker 的一种方式,在 Docker 6.0 中实现的方式是,为容器添加特权模式。如果你想把 Docker 本身作为一项服务提供给 Docker 容器,这个工具很有用。比如说,如果你想试用某种自动化工具或方法。请注意,Docker 的 “内部”实例是最新的 Docker二进制代码,构建时可以从 docker.io 来获取。另外牢记一点:以这种方式运行的实例是在特权模式下运行的;正因为如此,你将它们暴露在非 Docker 化的外界面前时,需要采取更多的防范措施。

dind一般分两种方式:

代码语言:javascript
复制
一种是使用宿主机的docker.sock,通过docker run -v /var/run/docker.sock:/var/run/docker.sock,将宿主机sock引入到容器内。这样当容器内使用docker命令时,实际上调用的是宿主机的docker daemon,这种方式速度快,但是安全性不够。
另一种是启动一个docker:dind容器a,再启动一个docker容器b,容器b指定host为a容器内的docker daemon;

在Kubernetes上运行的Docker构建(无论是使用JenkinsX,Tekton还是其他),您将需要Docker守护进程,该守护进程可以在Docker(DinD)中使用Docker进行部署,DinD是在Docker容器中运行的Docker守护进程。 至于构建本身,您将需要一个连接到DIND socket的pod(容器)来运行docker build命令。

代码语言:javascript
复制
apiVersion: v1
kind: Pod
metadata:
name: docker-build
spec:
containers:
- name: dind # Docker in Docker container
  image: docker:19.03.3-dind
  securityContext:
    privileged: true
  env:
  - name: DOCKER_TLS_CERTDIR
    value: ''
  volumeMounts:
    - name: dind-storage
      mountPath: /var/lib/docker
- name: docker # Builder container
  image: docker:19.03.3-git
  securityContext:
    privileged: true
  command: ['cat']
  tty: true
  env:
  - name: DOCKER_BUILDKIT
    value: '1'
  - name: DOCKER_HOST
    value: tcp://localhost:2375
volumes:
- name: dind-storage
  emptyDir: {}
- name: docker-socket-volume
  hostPath:
    path: /var/run/docker.sock
    type: File

上面的容器由2个容器组成—一个用于DinD,一个用于镜像构建。要使用构建容器运行构建,可以访问其shell,克隆一些存储库并运行构建流程:

~ $ kubectl exec –stdin –tty docker-build – /bin/sh # Open shell session ~ # git clone https://github.com/username/reponame.git # Clone some repository ~ # cd reponame ~ # docker build –build-arg BUILDKIT_INLINE_CACHE=1 -t name:tag –cache-from username/reponame:latest . … => importing cache manifest from martinheinz/python-project-blueprint:flask … => => writing image sha256:… => => naming to docker.io/library/name:tag => exporting cache => => preparing build cache for export

最终docker build使用了一些新选项—–cache-from image:tag,来告诉Docker它应该使用(远程)仓库中的指定镜像作为缓存源。这样,即使缓存的层未存储在本地文件系统中,我们也可以利用缓存的优点。 另一个选项—-build-arg BUILDKIT_INLINE_CACHE=1用于在创建缓存元数据时将其写入镜像。这必须用于–cache-from工作,有关更多信息,请参阅文档(https://docs.docker.com/engine/reference/commandline/build/#specifying-external-cache-sources)。

Kubernetes 之修改NodePort对外映射端口范围

k8s默认使用NodePort对外映射端口范围是30000-50000可以通过修改kube-apiserver参数修改端口范围 修改配置文件/opt/kubernetes/cfg/kube-apiserver增加或者修改以下配置 –service-node-port-range=30000-34000

代码语言:javascript
复制
# 样式命令一步到位
sed -i "/image:/i\    - --service-node-port-range=30000-34000" /etc/kubernetes/manifests/kube-apiserver.yaml
systemctl restart kubelet

Kubernetes 强制删除Pod、Namespace

描述: 在k8s中我们可能会遇到在删除一个pod时卡在了终端问题,一直terminating状态,此时我们可执行以下命令强制删除, 其中最主要的两个参数是--force --grace-period=0, 里面的 grace-period 参数会在Pod删除时此选项会起作用,缺省会延迟等待30s才会进行删除,当设置为0的时候表示立即删除。

代码语言:javascript
复制
# 删除POD
kubectl delete pod [pod name] --force --grace-period=0 -n [namespace]

# 删除NAMESPACE
kubectl delete namespace NAMESPACENAME --force --grace-period=0

Kubernetes 常规排错指南

0.节点kubelet相关信息

代码语言:javascript
复制
# 查看 kubelet 运行状态及其日志有无错误信息提示。
systemctl status kubelet
journalctl -xefu kubelet

# 查看 Conatinerd 运行状态及其日志有无错误信息提示。
systemctl status containerd
journalctl -xefu containerd

# 查看 docker 运行状态及其日志有无错误信息提示。
systemctl status docker
journalctl -xefu docker

1.节点状态及其相关信息

代码语言:javascript
复制
# 1.查看集群节点是否处于Ready状态。
kubectl get nodes -o wide |grep NotReady

# 2.如果是Ready状态请,查看节点描述信息以及资源信息。
kubectl describe nodes work-226

# 3.如果是NotReady状态,请查看对应节点上docker、containerd以及kubernetes相关。
$ ps aux|grep kube-proxy
$ ps aux|grep kubelet
$ ps aux|grep docker
$ ps aux|grep containerd

2.查看集群关键组件的状态是否是Healthy

代码语言:javascript
复制
~$ kubectl get cs
  Warning: v1 ComponentStatus is deprecated in v1.19+
  NAME                 STATUS    MESSAGE                         ERROR
  controller-manager   Healthy   ok
  scheduler            Healthy   ok
  etcd-0               Healthy   {"health":"true","reason":""}

如果状态都是Healthy的说明集群是正常,如果是Unhealthy状态, 则执行查询node对应的节点是否存在问题,如果存在需要登陆到对应节点上。

3.查看系统组件或者应用Pod状态及其日志

代码语言:javascript
复制
# 1.排查不是Running状态的Pod。
kubectl get pod -n kube-system | grep -v "Running"

# 2.排查Pod非Running状态的原因
kubectl describe pod -n kube-system kube-proxy-6jsmp

# 3.查看Pod日志信息
kubectl logs -f --tail 50 -n kube-system kube-proxy-6jsmp

10 个 Kubernetes 安全上下文配置

https://blog.csdn.net/qq_34556414/article/details/118683892

在 Kubernetes 中安全地运行工作负载是很困难的,有很多配置都可能会影响到整个 Kubernetes API 的安全性,这需要我们有大量的知识积累来正确的实施。Kubernetes 在安全方面提供了一个强大的工具 securityContext,每个 Pod 和容器清单都可以使用这个属性。在本文中我们将了解各种 securityContext 的配置,探讨它们的含义,以及我们应该如何使用它们。

代码语言:javascript
复制
securityContext 设置在 PodSpec 和ContainerSpec 规范中都有定义,这里我们分别用[P]和[C]来表示。需要注意的是,如果一个设置在两个作用域中都可以使用和配置,那么我们应该优先考虑设置容器级别的。

1runAsNonRoot [P/C]

我们知道容器是使用 namespaces 和 cgroups 来限制其进程,但只要在部署的时候做了一次错误的配置,就可以让这些进程访问主机上的资源。如果该进程以 root 身份运行,它对这些资源的访问权限与主机 root 账户是相同的。此外,如果其他 pod 或容器设置被用来减少约束(比如 procMount 或 capabilities),拥有一个 root UID 就会提高风险,除非你有一个非常好的原因,否则你不应该以 root 身份运行一个容器。

那么,如果你有一个使用 root 的镜像需要部署,那应该怎么办呢?

1.1 使用基础镜像中提供的用户

通常情况下,基础镜像已经创建并提供了一个用户,例如,官方的 Node.js 镜像带有一个 UID 为 1000 的名为 node 的用户,我们就可以使用该身份来运行容器,但他们并没有在 Dockerfile 中明确地设置当前用户。我们可以在运行时用 runAsUser 设置来配置它,或者用自定义的 Dockerfile 来更改镜像中的当前用户。这里我们来看看使用自定义的 Dockerfile 来构建我们自己的镜像的例子。

在不深入了解镜像构建的情况下,让我们假设我们有一个预先构建好的 npm 应用程序。这里是一个最小的 Dockerfile 文件,用来构建一个基于 node:slim 的镜像,并以提供的 node 用户身份运行。

代码语言:javascript
复制
FROM node:slim
COPY --chown=node . /home/node/app/   # <--- Copy app into the home directory with right ownership
USER 1000                             # <--- Switch active user to “node” (by UID)
WORKDIR /home/node/app                # <--- Switch current directory to app
ENTRYPOINT ["npm", "start"]           # <--- This will now exec as the “node” user instead of root

其中以 USER 开头的一行就是关键设置,这使得 node 成为从这个镜像启动的任何容器里面的默认用户。我们使用 UID 而不是用户的名字,因为 Kubernetes 无法在启动容器前将镜像的默认用户名映射到 UID 上,并且在部署时指定 runAsNotRoot: true,会返回有关错误。

1.2 基础镜像没有提供用户

如果我们使用的基础镜像没有提供一个可以使用的用户,那么我们又应该怎么做呢?对于大部分进程来说,我们只需在自定义的 Dockerfile 中创建一个用户并使用它即可。如下所示:

代码语言:javascript
复制
FROM node:slim
RUN useradd somebody -u 10001 --create-home --user-group  # <--- Create a user
COPY --chown=somebody . /home/somebody/app/
USER 10001
WORKDIR /home/somebody/app
ENTRYPOINT ["npm", "start"]

这里我们增加了一行创建用户的 RUN 命令即可。不过需要注意的是这对于 node.js 和 npm 来说,这很好用,但是其他工具可能需要文件系统的不同元素进行所有权变更。如果遇到任何问题,需要查阅对应工具的文档。 2runAsUser/runAsGroup [P/C]

容器镜像可能有一个特定的用户或组,我们可以用 runAsUser 和 runAsGroup 来进行覆盖。通常,这些设置与包含具有相同所有权 ID 的文件的卷挂载结合在一起。

代码语言:javascript
复制
....
spec:
  containers:
    - name: web
      image: mycorp/webapp:1.2.3
  securityContext:
    runAsNonRoot: true
    runAsUser: 10001
....

不过使用这些配置也是有风险的,因为你为容器做出的运行时决定可能与原始镜像不兼容。例如,jenkins/jenkins 镜像以名为 jenkins:jenkins 的组:用户身份运行,其应用文件全部由该用户拥有。如果我们配置一个不同的用户,它将无法启动,因为该用户不存在于镜像的 /etc/passwd 文件中。即使它以某种方式存在,它也很可能在读写 jenkins:jenkins 拥有的文件时出现问题。我们可以用一个简单的 docker 运行命令来验证这个问题。

代码语言:javascript
复制
$ docker run --rm -it -u eric:eric jenkins/jenkins
docker: Error response from daemon: unable to find user eric: no matching entries in passwd file.

上面我们提到确保容器进程不以 root 用户身份运行是一个非常好的主意,但不要依赖 runAsUser 或 runAsGroup 设置来保证这一点,未来有人可能会删除这些配置,请确保同时将 runAsNonRoot 设置为 true。

5避免使用特权容器 [C]

给容器授予特权模式是非常危险的,一般会有一种更简单的方式来实现特定的权限,或者可以通过授予 Linux Capabilities 权限来控制。容器运行时控制器着特权模式的具体实现,但是它会授予容器所有的特权,并解除由 cgroup 控制器执行的限制,它还可以修改 Linux 安全模块的配置,并允许容器内的进程逃离容器。

容器在宿主机中提供了进程隔离,所以即使容器是使用 root 身份运行的,也有容器运行时不授予容器的 Capabilities。如果配置了特权模式,容器运行时就会授予系统 root 的所有能力,从安全角度来看,这是很危险的,因为它允许对底层宿主机系统的所有操作访问。

避免使用特权模式,如果你的容器确实需要额外的能力,只需通过添加 capabilities 来满足你的需求。除非你的容器需要控制主机内核中的系统级设置,如访问特定的硬件或重新配置网络,并且需要访问主机文件系统,那么它就不需要特权模式。

代码语言:javascript
复制
securityContext:
  allowPrivilegeEscalation: true
  capabilities:
    drop:
      - ALL
    add:
      - NET_BIND_SERVICE
  # www-data -> 101
  runAsUser: 101

6Linux Capabilities [C]

Capabilities 是一个内核级别的权限,它允许对内核调用权限进行更细粒度的控制,而不是简单地以 root 身份运行。Capabilities 包括更改文件权限、控制网络子系统和执行系统管理等功能。在 securityContext 中,Kubernetes 可以添加或删除 Capabilities,单个 Capabilities 或逗号分隔的列表可以作为一个字符串数组进行配置。另外,我们也可以使用 all 来添加或删除所有的配置。这种配置会被传递给容器运行时,在它创建容器的时候会配置上 Capabilities 集合,如果 securityContext 中没有配置,那么容器将会直接容器运行时提供的所有默认配置。

代码语言:javascript
复制
securityContext:
  capabilities:
    drop:
      - all
    add: ["MKNOD"]

一般推荐的做法是先删除所有的配置,然后只添加你的应用程序实际需要的,在大部分情况下,应用程序在正常运行中实际上不需要任何 Capabilities,通过删除所有配置来测试,并通过监控审计日志来调试问题,看看哪些功能被阻止了。

请注意,当在 securityContext 中列出要放弃或添加的 Capabilities 时,你要删除内核在命名 Capabilities 时使用的 CAP_ 前缀。capsh 工具可以给我们一个比较友好的调试信息,可以来说明你的容器中到底启用了哪些 Capabilities,当然不要在生产容器中使用这个工具,因为这使得攻击者很容易弄清楚哪些 Capabilities 被启用了。


[root@weiyigeek-103 project]# kubectl label nodes aiserver accelerator=nvidia-tesla-v100 node/aiserver labeled [root@weiyigeek-103 project]# kubectl label nodes aiserver node-role.kubernetes.io/gpu-work= node/aiserver labeled

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-02-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Kubernetes 之修改NodePort对外映射端口范围
  • Kubernetes 强制删除Pod、Namespace
  • Kubernetes 常规排错指南
    • 0.节点kubelet相关信息
      • 1.节点状态及其相关信息
        • 2.查看集群关键组件的状态是否是Healthy
          • 3.查看系统组件或者应用Pod状态及其日志
          相关产品与服务
          容器服务
          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档