Docker Acemyzoe

GPU-server

构建GPU服务器的容器技术:Docker

远程登陆:SSH(局域网)

Hole : 使用Holer服务端软件搭建Holer服务,通过Holer客户端软件经自己服务器实现公网访问。

容器管理:DaoCloud - DCS


Docker

容器的本质是进程

Docker本身并不是容器,它是创建容器的工具,是应用容器引擎。

Docker技术的三大核心概念,分别是:

  • 镜像(Image)
  • 容器(Container)
  • 仓库(Repository)

安装

#安装docker
curl -sSL https://get.daocloud.io/docker | sh 

#安装nvidia-docker : https://github.com/NVIDIA/nvidia-docker
# Add the package repositories
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
sudo systemctl restart docker

#非root用户身份管理
sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker 

#配置docker自启动
sudo systemctl enable docker

命令

了解更多

#info
docker info
###################
#从dockerfile构建image
docker build -t <name>:<tag>  dockerfile_path
#从container构建image
docker commit container <images-name>:<tag>
#拉取镜像
docker pull tensorflow:latest
#查看image
docker images
#导出\导入镜像(优先)
docker save -o <name>.tar.gz <image-name>
docker load -i <name>.tar.gz 
#导出\导入容器(导入后cuda 失效)
docekr export -o <name>.tar.gz <container-name>
docker import <name>.tar.gz <images-name>:<tag>

####################
#创建container
docker run -ti \
                        --gpus all \
                        -p 6000:22 \
                        --name <name> \
                        -v server_dir : container_dir :ro \
                        -w container_dir
                        <image>
                        bash
#查看container
docker ps -a
#进入container ,attach可以带上--sig-proxy=false来确保CTRL-D或CTRL-C不会关闭容器
 docker attach <container-name>
 
#在运行的容器中执行命令。-d 后台运行;-i 保持STDIN打开;-t 分配伪终端
#可用于多终端,作用同tmux
docker exec -ti <container-name> bash

#查看容器中运行的进程信息
docker top <container-name>
#查看端口映射
docker port <contain-name>
#容器与主机之间的数据拷贝
docker cp container:path host-path

镜像加速

# 修改 /etc/docker/daemon.json 文件(如果没有,则创建)
vim /etc/docker/daemon.json
{
 "registry-mirrors": ["https://registry.cn-hangzhou.aliyuncs.com"],
 "registry-mirrors": ["https://registry.docker-cn.com"],
 "registry-mirrors": ["https://mirror.ccs.tencentyun.com"],
 "registry-mirrors": ["http://f1361db2.m.daocloud.io"]
}
systemctl daemon-reload
systemctl restart docker
systemctl start kubelet # 假设您安装了 kubenetes

docker info

Docker-compose

Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration. To learn more about all the features of Compose, see the list of features.

使用撰写三步骤:

  1. 定义Dockerfile或者镜像

    # syntax=docker/dockerfile:1
    FROM python:3.7-alpine
    WORKDIR /code
    ENV FLASK_APP=app.py
    ENV FLASK_RUN_HOST=0.0.0.0
    RUN apk add --no-cache gcc musl-dev linux-headers
    COPY requirements.txt requirements.txt
    RUN pip install -r requirements.txt
    EXPOSE 5000
    COPY . .
    CMD ["flask", "run"]
    
  2. 撰写docker-compose.yml

    version: "3.9"
    services:
      web:
        build: .
        ports:
          - "5000:5000"
        volumes:
          - .:/code
        environment: # 设置环境变量 ,就像docker run -e VARIABLE=VALUE 
          FLASK_ENV: development
      redis:
        image: "redis:alpine"
    volumes:
      logvolume01: {}
    

# Jenkins、Nginx的示例
version: '3'
services:
  docker_jenkins:
    user: root
    restart: always
    image: jenkinsci/blueocean
    container_name: jenkins
    ports:
      - 8080:8080
      - 50000:50000
    volumes:
      - /home/jenkins/jenkins_home/:/var/jenkins_name
      - /var/run/docker.sock:/var/run/docker.sock
      - /usr/bin/docker:/usr/bin/docker
      - /usr/local/bin/docker-compose:/usr/local/bin/docker-compose
      
  docker_nginx:
     user: root
     restart: always
     image: nginx
     container_name: nginx
     ports:
       - 80:80
       - 433:433
     volumes:
       - /data/nginx/conf.d:/etc/nginx/conf.d

       - /data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf
       - /data/nginx/log:/var/log/nginx
       - /data/nginx/html:/usr/share/nginx/html
  1. 运行docker-compose up

    # 不同yml
    docker-compose -f docker-compose.yml -f production.yml up -d
       
    # 特定service
    docker-compose build web
    docker-compose up --no-deps -d web
       
    # 其他
    docker-compse -h
    docker-compse ps
    docker-compose stop
    docker-compose down --volumes
    

K8S

kubernetes:容器编排解决方案,用来对容器化应用进行自动化部署、 扩缩和管理。

kuboard

K8S组件

  1. Master组件:集群控制平台
    • kube-apiserver:提供 Kubernetes API。Kubernetes管理工具:kubectl / kubernetes dashboard / kuboard
    • etcd:支持一致性和高可用的名值对存储组件。存储Kubernetes集群的所有配置信息。
    • kube-scheduler:监控所有新创建尚未分配到节点上的 Pod,并且自动为 Pod 选择合适的节点运行。
    • kube-controller-manager:运行了所有的控制器
  2. Node 组件:运行在每一个节点上(包括 master 节点和 worker 节点),负责维护运行中的 Pod 并提供 Kubernetes 运行时环境。
    • kubelet:运行在每一个集群节点上的代理程序,确保 Pod 中的容器处于运行状态。
    • kube-proxy:网络代理程序。
    • 容器引擎:docker、containerd

入门

Kubernetes 部署

Deployment 处于 master 节点上,通过发布 Deployment,master 节点会选择合适的 worker 节点创建 Container,Container 会被包含在 Pod里。

  • 通过kubectl部署nginx Deployment

    # 创建nginx-deployment.yaml
    apiVersion: apps/v1	#与k8s集群版本有关,使用 kubectl api-versions 即可查看当前集群支持的版本
    kind: Deployment	#该配置的类型,我们使用的是 Deployment
    metadata:	        #译名为元数据,即 Deployment 的一些基本属性和信息
      name: nginx-deployment	#Deployment 的名称
      labels:	    #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组
        app: nginx	#为该Deployment设置key为app,value为nginx的标签
    spec:	        #这是关于该Deployment的描述,可以理解为你期待该Deployment在k8s中如何使用
      replicas: 1	#使用该Deployment创建一个应用程序实例,用于应用程序的伸缩。
      selector:	    #标签选择器,与上面的标签共同作用,目前不需要理解
        matchLabels: #选择包含标签app:nginx的资源
          app: nginx
      template:	    #这是选择或创建的Pod的模板
        metadata:	#Pod的元数据
          labels:	#Pod的标签,上面的selector即选择包含标签app:nginx的Pod
            app: nginx
        spec:	    #期望Pod实现的功能(即在pod中部署)
          containers:	#生成container,与docker中的container是同一种
          - name: nginx	#container的名称
            image: nginx:1.7.9	#使用镜像nginx:1.7.9创建container,该container默认80端口可访问
    
    # 应用yaml文件
    kubectl apply -f nginx-deployment.yaml
    # 查看 Deployment
    kubectl get deployments
    # 查看 Pod
    kubectl get pods
    
  • 通过kuboard部署

查看Pods/Nodes

Pod 容器组 k8s 集群上的最基本的单元,是一组容器(可包含一个或多个应用程序容器),以及共享存储(卷 Volumes)、IP 地址和有关如何运行容器的信息。

同一 Pod 中的不同 container 端口不能相互冲突。同一个Pod内的容器可以使用 localhost + 端口号互相访问。

在 k8s 上创建 Deployment 时,会在集群上创建包含容器的 Pod (而不是直接创建容器)。每个Pod都与运行它的 worker 节点(Node)绑定,并保持在那里直到终止或被删除。如果节点(Node)发生故障,则会在群集中的其他可用节点(Node)上运行相同的 Pod(从同样的镜像创建 Container,使用同样的配置,IP 地址不同,Pod 名字不同)

Node(节点)是 kubernetes 集群中的计算机,可以是虚拟机或物理机。

kubernetes master 会根据每个 Node(节点)上可用资源的情况,自动调度 Pod(容器组)到最佳的 Node(节点)上

每个 Kubernetes Node(节点)至少运行:

  • Kubelet,负责 master 节点和 worker 节点之间通信的进程;管理 Pod(容器组)和 Pod(容器组)内运行的 Container(容器)。
  • 容器运行环境(如Docker)负责下载镜像、创建和运行容器等。
# kubectl get 资源类型
#获取类型为Deployment的资源列表
kubectl get deployments
#获取类型为Pod的资源列表
kubectl get pods
#获取类型为Node的资源列表
kubectl get nodes
# 查看所有名称空间的 Deployment
kubectl get deployments -A
kubectl get deployments --all-namespaces
# 查看 kube-system 名称空间的 Deployment
kubectl get deployments -n kube-system
# kubectl describe 资源类型 资源名称
#查看名称为nginx-XXXXXX的Pod的信息
kubectl describe pod nginx-XXXXXX	
#查看名称为nginx的Deployment的信息
kubectl describe deployment nginx	
# kubectl logs Pod名称
#查看名称为nginx-pod-XXXXXXX的Pod内的容器打印的日志
#本案例中的 nginx-pod 没有输出日志,所以您看到的结果是空的
kubectl logs -f nginx-pod-XXXXXXX
# kubectl exec Pod名称 操作命令
# 在名称为nginx-pod-xxxxxx的Pod中运行bash
kubectl exec -it nginx-pod-xxxxxx /bin/bash

公布应用程序-service

Service是一个抽象层,通过 LabelSelector 选择了一组 Pod(容器组),把这些 Pod 的指定端口公布到到集群外部,并支持负载均衡和服务发现。

  • 公布 Pod 的端口以使其可访问
  • 在多个 Pod 间实现负载均衡
  • 使用 Label 和 LabelSelector
# 创建nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service	#Service 的名称
  labels:     	#Service 自己的标签
    app: nginx	#为该 Service 设置 key 为 app,value 为 nginx 的标签
spec:	    #这是关于该 Service 的定义,描述了 Service 如何选择 Pod,如何被访问
  selector:	    #标签选择器
    app: nginx	#选择包含标签 app:nginx 的 Pod
  ports:
  - name: nginx-port	#端口的名字
    protocol: TCP	    #协议类型 TCP/UDP
    port: 80	        #集群内的其他容器组可通过 80 端口访问 Service
    nodePort: 32600   #通过任意节点的 32600 端口访问 Service
    targetPort: 80	#将请求转发到匹配 Pod 的 80 端口
  type: NodePort	#Serive的类型,ClusterIP/NodePort/LoaderBalancer
kubectl apply -f nginx-service.yaml
kubectl get services -o wide
curl <任意节点的 IP>:32600

滚动更新Rolling Update

滚动更新允许以下操作:

  • 将应用程序从准上线环境升级到生产环境(通过更新容器镜像)
  • 回滚到以前的版本
  • 持续集成和持续交付应用程序,无需停机
# 前提是将应用程序 Scale Up(扩容)为多个实例。
replicas: 4
image: nginx:1.8   #使用镜像nginx:1.8替换原来的nginx:1.7.9
kubectl apply -f nginx-deployment.yaml
# 执行命令,可观察到 pod 逐个被替换的过程
watch kubectl get pods -l app=nginx

进阶

架构

  • 节点

    • 节点信息(由节点上的 kubelet 收集)

      kubectl get nodes -o wide
      kubectl describe node <your-node-name>
      
    • 节点管理(组件Node Controller)

      # 手动将节点标记为不可调度(unschedulable),阻止新的 Pod 被调度到该节点上,但是不影响任何已经在该节点上运行的 Pod。这在准备重启节点之前非常有用。
      kubectl cordon $NODENAME
      
  • 集群内的通信(从单master到k8s高可用)

    • Cluster to Master

    所有从集群访问 Master 节点的通信,都是针对 apiserver 的。apiserver 监听 HTTPS 端口(443)并配置授权方式。

    • Master to Cluster

      • apiserver 访问集群中每个节点上的 kubelet 进程
      • 使用 apiserver 的 proxy 功能,从 apiserver 访问集群中的任意节点、Pod、Service

操作k8s

  • k8s对象

  • namespace

    # 查看集群中的名称空间列表
    kubectl get namespaces --show-labels
    # 查看名称空间的概要信息
    kubectl describe namespaces <name>
    # 直接使用命令创建删除名称空间:development 和 production
    kubectl create namespace <名称空间的名字>
    kubectl delete namespaces <名称空间的名字>
    
  • 标签

容器

  • 容器生命周期事件处理

    Kubernetes 中支持容器的 postStart 和 preStop 处理程序(handler)。

    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: ["/bin/sh","-c","nginx -s quit; while killall -0 nginx; do sleep 1; done"]
    

工作负载

  • Pod容器组

    将多个容器运行于同一个容器组中是一种相对高级复杂的使用方法。只有在您的容器相互之间紧密耦合是,您才应该使用这种方式。例如:您可能有一个容器是 web server,用来将共享数据卷中的文件作为网站发布出去,同时您有另一个 “sidecar” 容器从远程抓取并更新这些文件。

  • Deployment控制器

    用户应该始终使用控制器来创建 Pod,而不是直接创建 Pod,控制器可以提供如下特性:

    • 水平扩展(运行 Pod 的多个副本)
    • rollout(版本更新)
    • self-healing(故障恢复)

MORE