Docker 及 nvidia-docker 使用
Docker 基本用法
1. 安装社区版docker-ce 及 nvidia-docker2 插件
通过官网介绍的软件源的方式安装. 如果要安装nvidia-docker,由于其需要与docker-ce的版本匹配,所以如果是手动下载安装的话需要注意版本号.
nvidia-docker对宿主机的要求是安装了nvidia驱动程序和docker程序,而CUDA toolkit安装在容器里边,而不必安装在宿主机上. 因此包含cuda toolkit的镜像通常都很大.
安装之后重载Docker daemon: sudo pkill -SIGHUP dockerd
运行示例: docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi
离线安装: ubuntu下借助apt-rdepends找出所有的递归依赖: apt-get download $(apt-rdepends docker-ce|grep -v "^ ")
CentOS等其它版本的安装参考: https://github.com/gzvincen/docker-offline-install-package
nvidia深度学习开发栈如下图所示:
2. 镜像加速
对于使用 upstart 的系统而言,编辑 /etc/default/docker 文件,在其中的 DOCKER_OPTS 中配置加速器地址:
DOCKER_OPTS="--registry-mirror=https://registry.docker-cn.com"
或者daocloud的http://4ce12ab7.m.daocloud.io
重新启动服务:
sudo service docker restart
3. 建立 docker 用户组
默认情况下,docker 命令会使用 Unix socket 与 Docker 引擎通讯。而只有 root 用户和 docker 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 root 用户。因此,更好地做法是将需要使用 docker 的用户加入 docker 用户组。
建立 docker 组:
sudo groupadd docker
将当前用户加入 docker 组:
sudo usermod -aG docker $USER
退出当前终端并重新登录才可生效(如果急用,运行docker时加sudo)。
4. 运行容器
docker run -dit ubuntu
加--rm参数,在容器终止运行后自动删除容器文件。
5. 进入容器命令行
docker attach 243c
# 如果镜像的入口并非shell,则不能够进入shell,需要执行 docker exec
docker exec -it 69d1 bash
6. 容器与宿主机互相拷贝文件: docker cp
Usage: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
7. 将容器保存为镜像:
docker commit 容器id 镜像名称
8. 上传镜像到仓库:
打tag: docker tag 镜像名称 远程镜像名称tag
docker image ls
进行查看
上传docker push 远程镜像名称tag
为了加速, 可以使用HTTPS_PROXY=https://xxx docker push
9. 停止容器: docker stop --time=20 container_name
会发送信号SIGTERM并等待一定时间后终止.
docker kill
发出SIGKILL 强制终止
10. 删除已停止的容器: 较新版的删除所有已停止的容器快捷方式: docker container prune
查出容器的 ID: docker container ls --all
删除指定的容器文件 docker container rm [containerID]
删除镜像 docker rmi -f [image ID]
如果有对应的启动的容器需要-f
(force)一并删除
11. 列出容器: 正在运行中的程序: docker ps
, 使用-a
包括已停止的容器.
12. 镜像无法联网, 可尝试在docker run时加 --net host
13. 启动已经终止的容器: docker start 容器id
14. detach 即退出容器shell而不终止容器: Ctrl+p + Ctrl+q
15. 容器导出/导入到文件
docker export -o project-image.tar 45589e5912ce
导入容器镜像用import : docker import my_ubuntu_v3.tar runoob/ubuntu:v4
可以将导入的镜像命名为后者, 如果不命名,则是<none>
. 另外,还可以用save命令将镜像完整保存,包括历史版本和元数据信息,所以文件可能比较大。相应的用load命令导入: docker load < project-image.tar
导入之后通过docker images
命令可以看到新导入的镜像.
区别是export导出的是容器, save导出的是镜像, 另外,最好用save导出比较完整,否则容易出现cuda与驱动不匹配的问题.
另外,导出到文件时进行压缩可节省空间:
导出镜像: docker save ubuntu:v4 | gzip -c > ubuntu-v4.tgz
导入镜像: gunzip -c project-v2.tgz | docker load
16. 移除所有的容器和镜像(大扫除):
docker kill $(docker ps -q) ; docker rm $(docker ps -a -q) ; docker rmi $(docker images -q -a)
17. 验证GPU可用性: docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi
--rm 表示运行完毕就删除容器, -dit -d表示以daemon后台运行, -i交互式-t新的伪终端.
如果不加-it运行的时候无法接受ctrl+c等输入.
容器的启动方式: nvidia-docker start 071b0b
Docker 更多介绍
关于网络配置
在使用默认的桥接模式下,容器启动后会被分配一个与docker0在同一网段的地址,在容器内部默认显示为eth0,在宿主机上产生一个临时的vethXXX接口。
端口映射
在主机上查看端口映射的方式为docker ps(桥接方式会显示端口)、docker inspect [id]、netstat -nlp
netstat可能只会显示出tcp6的监听状态,实际上ipv4的地址也监听了。
在访问容器内的服务时,如将mysql的3306端口映射到主机上的13306端口,则通过13306端口通信时客户端使用的是docker0的地址,需要配置mysql容许建立连接的ip地址。除了设置bind-address外,可能还需要设置特定用户的权限:
update user set host='%或者ip' where xxx;
flush privileges;
可以通过命令
telnet localhost 13306
来检测是否能够建立tcp连接
容器连接
由于容器间应用程序被相互隔离,在不使用--link连接容器时难以从一个容器内建立到另外一个容器内的进程的连接,除非使用共享的socket文件来实现unix socket通信(挂载相同的卷或者同样具有对某一系统目录的写权限)。在知道容器的ip时可以发送ping ICMP数据包
要建立容器之间的链接,必须在启动时通过参数--name $container_name给容器命名
--link name:alias Docker在两个容器之间创建了一个安全的隧道,这是链接的巨大优势, 通过连接,我们不需要向外部网络暴露端口.
在连接了目标容器后,我们可以在源容器中查看到/etc/hosts文件中多了一个目标容器的host解析:
172.17.0.2 alias 13065893a1dd name
执行netstat -nlt不能够看到目标容器中开放的端口,但是可以访问。
容器的hostname
在用docker运行一个镜像时如果使用桥接方式,没有用-h指定hostname,则使用产生的容器id的一部分作为hostname,解析为容器内eth0的地址。如果需要连接两个容器,最好是指定hostname而不是ip的形式来建立tcp连接。
如果通过--net='host'指定容器使用host的网络配置,那么hostname、网络接口、dns等信息完全一样。
容器内的网络配置是只读的,如果想要在容器内修改配置,需要在运行时加上参数--cap-add=NET_ADMIN来赋予修改权限(如果采用了host方式会影响到host主机的网络配置)。
数据存储
容器停止后再次运行时(docker start)上次修改后的数据得以保留,不会丢失。而从镜像重新创建一个容器运行时是镜像原本的数据。
将数据从容器中拷出来:
docker cp containerId:/file/path/within/container /host/path/target
更方便的方式可能就是使用-v挂载外部卷了,直接在容器外部的文件中读写。