这篇文章讲解的容器运行时是docker,containerd有些许不一样
pod里的所有容器,共享的是同一个Network Namespace,并且可以声明共享同一个Volume。
1.infra容器
在k8s项目中,Pod只是一个逻辑概念,在具体实现上,还是通过yaml来创建container。
在一个pod中可以创建多个容器,上面说了,pod中的多个容器是共享同一个Network Namespace的,并且pod中定义的多个容器是相同级别的,那多个容器的创建没有先后之分,是怎样共用Network Namespace的呢??
这里就是通过infra中间容器,这个容器永远都是第一个被创建。
1.1infra容器介绍
infra容器占用很少的资源:所以它使用一个特殊的镜像:k8s.gcr.io/pause,阿里云上创建的容器,使用的镜像是:registry.aliyuncs.com/google_containers/pause:3.1,这个镜像永远处于“暂停”状态。
infra容器第一个被创建:pod中定义的容器与infra容器使用相同的network namespace
即,对于pod中的A、B容器来说:
1.两个容器网络互通,可以使用localhost通信。
2.infra容器和A、B容器的网络设备相同。
3.一个pod只有一个Ip,即是这个共同的Network Namespace的Ip地址。
4.pod的生命周期只和infra容器一致,与A 、B 容器无关。
5.pod中流量的进出,可以认为是通过Infra容器完成的。所以开发网络插件时,只需要考虑如何配置这多个容器共享的network namespace。
1.2pod中包含多个容器演示案例
1.准备pod yaml
apiVersion v1
kind Pod
metadata
name two-containers
spec
nodeName testops #这里我只在这个节点上测试,所以写了一个固定的节点
containers
name blue-pod-container
image busybox1.31.1
command"sleep"
args"10000"
name green-pod-container
image busybox1.30.1
command"sleep"
args"10000"
2.查看该pod创建的容器
[root@testops ~]# docker ps -a|grep two-containers
50088eed88a7 busybox "sleep 10000" 5 seconds ago Up 4 seconds k8s_green-pod-container_two-containers_default_51ed090c-5852-425c-8903-60bc88758ba1_0
a2882bdb45aa busybox "sleep 10000" 12 seconds ago Up 11 seconds k8s_blue-pod-container_two-containers_default_51ed090c-5852-425c-8903-60bc88758ba1_0
72ad9f8e2891 registry.aliyuncs.com/google_containers/pause:3.1 "/pause" 19 seconds ago Up 18 seconds k8s_POD_two-containers_default_51ed090c-5852-425c-8903-60bc88758ba1_0
3.查看每个容器的pid和network namespace
测试发现,以下三个namespace相同。
lrwxrwxrwx 1 root root 0 Jan 27 22:25 ipc -> ipc:[4026535040]
lrwxrwxrwx 1 root root 0 Jan 27 22:25 net -> net:[4026535043]
lrwxrwxrwx 1 root root 0 Jan 27 22:26 user -> user:[4026531837]
[root@testops ~]# docker inspect --format '{{ .State.Pid }}' 50088eed88a7
2983
[root@testops ~]# docker inspect --format '{{ .State.Pid }}' a2882bdb45aa
2314
[root@testops ~]# docker inspect --format '{{ .State.Pid }}' 72ad9f8e2891
1729
[root@testops ~]# ll /proc/2983/ns/
total 0
lrwxrwxrwx 1 root root 0 Jan 27 22:26 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Jan 27 22:25 ipc -> ipc:[4026535040]
lrwxrwxrwx 1 root root 0 Jan 27 22:25 mnt -> mnt:[4026535121]
lrwxrwxrwx 1 root root 0 Jan 27 22:25 net -> net:[4026535043]
lrwxrwxrwx 1 root root 0 Jan 27 22:25 pid -> pid:[4026535123]
lrwxrwxrwx 1 root root 0 Jan 27 22:26 pid_for_children -> pid:[4026535123]
lrwxrwxrwx 1 root root 0 Jan 27 22:26 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Jan 27 22:25 uts -> uts:[4026535122]
[root@testops ~]# ll /proc/2314/ns/
total 0
lrwxrwxrwx 1 root root 0 Jan 27 22:26 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Jan 27 22:25 ipc -> ipc:[4026535040]
lrwxrwxrwx 1 root root 0 Jan 27 22:25 mnt -> mnt:[4026535117]
lrwxrwxrwx 1 root root 0 Jan 27 22:25 net -> net:[4026535043]
lrwxrwxrwx 1 root root 0 Jan 27 22:25 pid -> pid:[4026535120]
lrwxrwxrwx 1 root root 0 Jan 27 22:26 pid_for_children -> pid:[4026535120]
lrwxrwxrwx 1 root root 0 Jan 27 22:26 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Jan 27 22:25 uts -> uts:[4026535118]
[root@testops ~]# ll /proc/1729/ns/
total 0
lrwxrwxrwx 1 root root 0 Jan 27 22:26 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Jan 27 22:25 ipc -> ipc:[4026535040]
lrwxrwxrwx 1 root root 0 Jan 27 22:25 mnt -> mnt:[4026535038]
lrwxrwxrwx 1 root root 0 Jan 27 22:25 net -> net:[4026535043]
lrwxrwxrwx 1 root root 0 Jan 27 22:25 pid -> pid:[4026535041]
lrwxrwxrwx 1 root root 0 Jan 27 22:26 pid_for_children -> pid:[4026535041]
lrwxrwxrwx 1 root root 0 Jan 27 22:26 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Jan 27 22:25 uts -> uts:[4026535039]
[root@testops ~]#
2.pod介绍
2.1特殊字段介绍
2.2.1hostAliases设置/etc/hosts文件
在k8s中,如果要设置hosts文件,一定要通过这种方式,否则pod删除重建后,会覆盖掉被修改的内容。
---
apiVersion v1
kind Pod
metadata
name two-containers
spec
hostAliases
ip"10.1.2.3"
hostnames
"foo.remote"
"bar.remote"
nodeName testops-k8s03-worker01
containers
name blue-pod-container
image busybox1.31.1
command"sleep"
args"10000"
查看/etc/hosts文件内容
✘ dz0400819@MacBook-Pro ~/.kube kubectl exec -it two-containers /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
172.29.1.52 two-containers
# Entries added by HostAliases.
10.1.2.3 foo.remote bar.remote
/ #
2.2.2pod lifecycle字段
podtsStart:容器启动后,立刻执行的操作。
postStart的执行是异步的,postStart 定义的操作,虽然是在 Docker 容器 ENTRYPOINT 执行之后,但它并不严格保证顺序。也就是说,在 postStart 启动时,ENTRYPOINT 有可能还没有结束。
preStop:在容器被杀死之前(如:收到SIGKILL信号)。
preStop的执行是同步的,所以会先执行preStop中的操作,操作完成后才会杀死容器。
在这个例子中,在容器被杀死之前,先调用nginx退出命令来实现nginx的优雅推出。
apiVersion v1
kind Pod
metadata
name lifecycle-demo
spec
containers
name lifecycle-demo-container
image nginx
lifecycle
postStart
exec
command"/bin/sh" "-c" "echo Hello from the postStart handler > /usr/share/message"
preStop
exec
command"/usr/sbin/nginx""-s""quit"
注意:
上面说到了sigKill信号,这里多介绍一下删除pod的过程。
删除pod -> 执行preStop -> done收到KiLL信号 -> server端优雅终止 -> 删除pod
package main
import (
"context"
"flag"
"fmt"
"io"
"math/rand"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
"strings"
"syscall"
"time"
"github.com/golang/glog"
)
func main() {
flag.Set("v", "4")
glog.V(2).Info("Starting service0")
mux := http.NewServeMux()
mux.HandleFunc("/", healthz)
srv := http.Server{
Addr: ":80",
Handler: mux,
}
done := make(chan os.Signal, 1)
//用于接收Kill信号
signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
glog.Fatalf("listen: %s\n", err)
}
}()
glog.Info("Server Started")
<-done
glog.Info("Server Stopped")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer func() {
// extra handling here
cancel()
}()
if err := srv.Shutdown(ctx); err != nil {
glog.Fatalf("Server Shutdown Failed:%+v", err)
}
glog.Info("Server Exited Properly")
}
func healthz(w http.ResponseWriter, r *http.Request) {
for k, v := range r.Header {
io.WriteString(w, fmt.Sprintf("%s=%s\n", k, v))
}
io.WriteString(w, "ok\n")
}