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深度学习开发栈如下图所示:

nvidia-docker-stack

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挂载外部卷了,直接在容器外部的文件中读写。

posted @ 2016-04-26 17:52  康行天下  阅读(13558)  评论(0编辑  收藏  举报