Docker实践
Posted on Aug.1, 2020
简介
- 什么是Docker
Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 OverlayFS 类的 Union FS 等技术, 对进程进行封装隔离,属于 操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。
传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程; 容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。
・更高效的利用系统资源; ・更快速的启动时间; ・一致的运行环境; ・持续交付和部署; ---> 开发通过Dockerfile构建镜像,并结合持续集成系统进行集成测试,甚至结合持续部署系统进行自动部署。 ・更轻松的迁移; ・更轻松的维护和扩展. ---> Docker使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。 此外,Docker团队同各个开源项目团队一起维护了一大批高质量的官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。 特性 容器 虚拟机 启动 秒级 分钟级 硬盘使用 一般为 MB 一般为 GB 性能 接近原生 弱于 系统支持量 单机支持上千个容器 一般几十个
基本概念
理解了这三个概念,就理解了 Docker 的整个生命周期。- 镜像 image
- 容器 container
'镜像与容器'类似'类与实例'的关系。 容器运行时 = 镜像(基础层) + 运行时的读写(容器存储层),但Docker最佳实践的要求是所有文件写入操作,都应该使用数据卷(Volume)或者绑定宿主目录。因为容器和存储层是有生存周期的。
查看镜像:docker image ls 或 nvidia-docker image ls 查看容器:docker ps -a
需要一个集中的存储、分发镜像的服务 ———— Docker Registry 服务 Registry │ | 仓库 |—— Repository 1 |—— Repository 2 | . . . └───Repository n | │ 标签 │—— Tag 1 |—— Tag 2 | . . . └—— Tag n ———— Each tag corresponds to a image. 比如一个仓库包含同一个软件不同版本的镜像。 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。 例: ubuntu:16.04, ubuntu:18.04, ubuntu:latest 仓库名经常以两段式路径 形式出现,如 devonnhou/pytorch1.5 最常使用的 Registry 公开服务是官方的 Docker Hub,这也是默认的 Registry,并拥有大量的高质量的官方镜像。 Docker Hub 国内加速器下载Docker Hub的镜像更快,如阿里云加速器
实战篇
https://zhuanlan.zhihu.com/p/23599229安装和卸载
Docker可以安装在Windows、Linux、Mac等各个平台上。具体可以查看文档Install Docker。安装完成之后,可以查看Docker的版本信息:# docker version
查看Docker的帮助信息:# docker --help。各种命令的用法也不再赘述,后边用到哪些命令时会作出一定的解释。
关于镜像的基本操作
在dockerhub选择镜像时,比如为pytorch构建的不同tag的cuda镜像区别: base:基于cuda,包含最精简的依赖,用于部署预编译的cuda应用,需要手动安装所需的其他依赖 runtime:基于base,添加了cuda toolkit共享的库,涵盖了运行环境的最小集合如动态库等,但没有cuda的编译工具nvcc devel:基于runtime,添加了编译工具链、调试工具、头文件、静态库,用于从源码编译cuda应用,是有nvcc的
关于容器的基本操作
docker run -it --runtime=nvidia -p 9999:22 --restart=always --ipc=host -v /data/houdewang/containers-shared:/containers-shared --name=super-resolution hdw-pytorch:1.7.0 bash 通过宿主机的9999端口可以ssh登录到容器中 (和vscode的remote-SSH功能搭配使用,很方便) -v 把宿主机上的目录映射到容器内 这样进去的用户名默认都是root,如果为了方便主环境管理员,可以把起容器的命令改进,加一组参数-v /etc/passwd:/etc/passwd -u $(id -u):$(id -g),使得容器内外的用户名一致。
相关:新账户的创建 sudo useradd -m eric -s /bin/bash sudo passwd eric sudo gpasswd -a eric docker # gpasswd的设计初衷是与组相关的密码管理。早期某些组可以设置密码以限制访问。但现代Linux系统中的组通常不使用密码。所以现在gpasswd仅用于添加和删除组成员。尽管它的名字中包含“passwd”,但它并不用于设置或修改用户的登录密码。这里我们组名就叫docker,sudo groupadd mygroup可以创建组。 newgrp docker # 启动一个新的shell会话,并将当前会话的有效组更改为指定的组。 cd /data sudo mkdir eric sudo chown -R eric eric
退出容器并结束容器运行 exit 返回容器 先start,再attach 退出容器但容器仍运行 Ctrl+P+Q 返回容器 docker attach container_id (或 docker exec -it container_id bashShell) 进不去使用 docker exec -it containerID /bin/bash
本地浏览器连容器内的tensorboard: 1.创建容器时 -p 6166:6166/tcp -p 6167:6167/tcp 多映射几对端口。(平时9999:22,是因为ssh一般默认22端口) 2.tensorboard --logdir dirname --bind_all --port 6167,可以tensorboard -h查看--bind_all的作用,可以知道它能将TensorBoard实例暴露给公网。 3.本地浏览器输入 http://服务器IP:6166
修改虚拟网卡ip: 配置文件添加 --bip,设置合适的地址。不然会报错。 step1: 删除原有配置 https://www.jianshu.com/p/c06d532ec8f8 step2: 修改docker配置 https://stackoverflow.com/questions/52225493/change-default-docker0-bridge-ip-address
注意:在docker内查看nvidia-smi是不显示进程号(pid), 回到服务器账户看就好啦
关于在远程容器中使用jupyter
对于一些教程类型的code,我们经常需要用到jupyter。那么如何在本地利用远程服务器的算力和docker容器启动jupyter呢? step1: 首先创建容器时,就记得提前多留出一个特定端口 docker run -it --runtime=nvidia -p 9999:22 10000:8888 ... step2: 安装jupyter并进行配置 安装:pip install notebook 生成配置文件:jupyter notebook --generate-config 修改配置:vim ~/.jupyter/jupyter_notebook_config.py c.NotebookApp.ip='*' #表示同一网络的主机都可访问 c.NotebookApp.password = u'sha1密文' c.NotebookApp.open_browser = False c.NotebookApp.port =8888 #随便指定一个 第二行的密码是可选的,为了安全起见,我们可以生成一个。 In [1]: from notebook.auth import passwd In [2]: passwd() Enter password: Verify password: # 粘贴到c.NotebookApp.password = u'sha1密文'这儿 Out[2]:'sha1:xxxxxxxxx:xxxxxxxxxxxxxxxxxxxxx' step3: 启动jupyter并在本地浏览器打开: 启动:jupyter notebook url:服务器IP:10000 (对应创建容器时的-p设置) step4: 输入密码
关于vscode进入远程容器
设置管理员密码 passwd root enable管理员远程登录 sudo service ssh start sudo vim /etc/ssh/sshd_config PermitRootLogin 改为yes 容器内open-ssh开机自动启动 sudo service ssh restart sudo apt update && apt install systemd && systemd enable ssh Open SSH Configuration File... HostName和宿主机一致,端口用9999 Connect to Host...
Kubernetes(常简称为K8s)旨在提供跨主机集群的平台。它支持一系列容器工具,包括Docker等。
Kubectl基本命令
假设资源组namespace叫video ・ cd k8s folder ・ Run: sudo kubectl apply -f・ Check status: sudo kubectl get pod -n video ・ Check real-time logs: sudo kubectl logs -n video ・ Stop: sudo kubectl delete –f (Pod: Kubernetes的基本调度单元称为“pod”。)
同时可以在~/.bashrc定义快捷方式 # shortcut for kubectl commands alias kapply="sudo kubectl apply -f" alias kstat="sudo kubectl get pod -n video" alias kdel="sudo kubectl delete -f" alias klog="sudo kubectl logs -n video -f" 最后一个添加了-f,会stream log (持续更新log),不加-f是一次性显示那一时刻的log。
最后,最自由的使用方式是进入容器内。 sudo kubectl exec -it-n video -- /bin/bash 进 exit 出 也可以定义快捷方式 alias kexec='AttachDocker(){ sudo kubectl exec -it $1 -n video -- /bin/bash;};AttachDocker' 进容器后做什么都可以,但不要kill这个pod任务里的进程,不然当前pod会报Error,然后K8s又自动重新帮你开一个新的pod。 可以在启动脚本里加一句 date;sleep 2m;date 搭配使用,在训练开始的2分钟前,kexec进去安装或修改一些必要的库。
查看节点gpu数量: kubectl get nodes "-o=custom-columns=NAME:.metadata.name,GPU:.status.allocatable.nvidia\.com/gpu" 查看现有任务所用的节点: sudo kubectl get pod -n kube-system -o wide -n video
搭配NFS存储服务器
现在比较流行的是挂载NFS网络盘,适合深度学习批量传输小文件的需求。 sudo mount -t nfs -o rw xx.xx.xx.xx(IP):/export/xx(remote directory) /home/xx(local directory) mount [-t vfstype] [-o options] device dir 其他参数见 https://www.cnblogs.com/linuxprobe/p/5473645.html
docker存储清理
docker system prune -a && docker volume prune 前一个命令安全,后一个不到不得已慎用。 BE CAREFUL docker volume prunewill remove all your data that was persisted from docker to host disk........ system prune is safe though 清理容器前,可以查看容器状态: docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}"
docker存储的维护: docker system df 查看存储占用情况, docker rmi IMAGE 指定删除镜像 docker rm CONTAINER 指定删除容器 docker system prune = docker image prune + docker container prune + docker network prune 自动清理未使用的镜像/容器/网络等。
docker存储迁移
docker安装时,存储位置默认在/var/lib/docker。一般这个是挂载在系统盘。而系统盘一般空间较小,无法满足docker用户增长的需求。并且出问题会带来一些风险。放数据盘更安全。1. sudo systemctl stop docker 且 systemctl stop docker.socket 2. sudo cp -rp /var/lib/docker/* /新的存储位置/ 或 sudo rsync -aqxP /var/lib/docker/ /新的存储位置/ 3. sudo rm -rf /var/lib/docker 4. sudo ln -s /新的存储位置/ /var/lib/docker 或 3. 更新docker配置文件 /etc/docker/daemon.json { "data-root": "/新的存储位置/" } 4. 保存和关闭配置文件 5. sudo systemctl start docker
制作docker镜像
How to write dockerfile除了使用docker镜像,很多时候我们需要制作镜像,来完成服务器部署。 常见流程:编写dockerfile→jenkins编译→发布到jfrog