Docker是个好东西,或者说容器是个好东西。 毕竟回忆里的昨天,我再也回不去。
但容器可以。

Docker存储方式

还是先说一下Docker容器的储存结构,容器镜像采用的是分层存储的方式,下面是一个Ubuntu16.04的镜像结构。

docker

也可以在命令行观察,在拉取的时候也可以看到结果:

bash
 $ docker pull ubuntu:16.04
 16.04: Pulling from library/ubuntu
 3b37166ec614: Already exists
 504facff238f: Already exists
 ebbcacd28e10: Already exists
 c7fb3351ecad: Already exists
 2e3debadcbf7: Already exists
 Digest: sha256:45ddfa61744947b0b8f7f20b8de70cbcdd441a6a0532f791fd4c09f5e491a8eb
 Status: Downloaded newer image for ubuntu:16.04

其中,每层表示的是与上一层的差异,而不是直接操作底层镜像,这样,当使用其他基于此镜像制作的镜像时,就不必整个拉取或者复制过来,因为它们很多的底层镜像是一样的。Docker镜像采用的是共享存储方式,当拉取一个镜像时,会首先获取所有层的信息,如果该镜像层本地已经有了,就不用下载,只需要下载所需要的镜像层。

docker

在使用镜像建立容器时候,会在最上面一层镜像上建立一个可写层,即容器层。当在容器中所有的操作都会被保存在这个可写层,如果直接删除容器,则可写层就会被删除,即使利用相同镜像重新建立容器,之前的所有操作也不会被保存。镜像层都是只读的,基于此安全性,所有的容器都可以访问底层镜像,所以一次可以利用同一镜像建立多个容器。最后完成修改封装成新的容器的时候,也只是在原来的镜像层之上又加了一层而已。镜像的这种共享存储方式可以极大地提高资源利用效率,而差异存储也是文件管理的主流之选。

说到这个,想起来目前有个PWD(Play with Docker)的网站,可以直接在里面体验docker,地址在这。进去就可以创建一个Docker playground。

docker

利用Docker运行CUDA和TensorFlow

在电脑上配置CUDA或者TensorFlow啥的,经常因为各种版本不同导致一大堆问题,于是就想看看可不可以利用Docker去解决这个问题,每次直接打开封装好的镜像就行了,让Docker里的环境去使用GPU,不用去配环境,也不用在电脑上装啥别的软件。然后发现NVIDIA也在Docker上稍微封装了一下,弄了个Nvidia-docker命令,基本命令与docker命令一样,唯一的区别是普通的Docker无法使用GPU,所以Nvidia-docker等效于命令docker --runtime=nvidia

要使用GPU,首先也要安装好显卡驱动,怎么安装这里不做赘述,通常安装成功是可以看到的。

当然,Docker肯定要先装好。

Nvidia Docker

然后就是安装Nvidia封装的Docker来调用GPU了,具体可以参照NVIDIA/nvidia-docker页面。

如果之前有安装1.0版本的Nvidia-docker的,需要先卸载:

bash
# If you have nvidia-docker 1.0 installed: we need to remove it and all existing GPU containers
docker volume ls -q -f driver=nvidia-docker | xargs -r -I{} -n1 docker ps -q -a -f volume={} | xargs -r docker rm -f
sudo apt-get purge -y nvidia-docker

没有的话可以直接略过。然后添加仓库地址重定向到镜像源文件中,再更新软件源。

bash
# Add the package repositories
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | \
  sudo apt-key add -
  distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
  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

然后直接安装即可。

bash
# Install nvidia-docker2 and reload the Docker daemon configuration
sudo apt-get install -y nvidia-docker2
sudo pkill -SIGHUP dockerd

CUDA测试

首先运行一个cuda的镜像,进入bash中,

 docker run --runtime=nvidia -it --name cuda --rm nvidia/cuda:9.0-base /bin/bash
 root@c1d523d61051:/#
 root@c1d523d61051:/#

这里将容器命名为cuda方便操作,需要选择runtime为nvidia,或者直接使用nvidia-docker命令。然后输入nvidia-smi就可以看到是否成功调用显卡了。

root@c1d523d61051:/# nvidia-smi 
Thu Oct 11 07:51:19 2018       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 384.130                Driver Version: 384.130                   |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 1080    Off  | 00000000:01:00.0  On |                  N/A |
|  0%   44C    P8    14W / 200W |    867MiB /  8110MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+

TensorFlow测试

刚刚也说了,如果要使用GPU,需要在docker命令中加上--runtime=nvidia或者直接使用nvidia-docker命令。这里就直接使用nvidia-docker命令了,

bash
 $ nvidia-docker run -it -d --name tensor -p 8888:8888 tensorflow/tensorflow 
9c7db93b36788acf61a20f52cb187f32e0d6018f7e8da031a30fa135252a4896

查看容器内信息,

docker logs tensor
[I 08:01:55.452 NotebookApp] Writing notebook server cookie secret to /root/.local/share/jupyter/runtime/notebook_cookie_secret                                                                                                                              
[I 08:01:55.465 NotebookApp] Serving notebooks from local directory: /notebooks
[I 08:01:55.465 NotebookApp] The Jupyter Notebook is running at:
[I 08:01:55.465 NotebookApp] http://(9c7db93b3678 or 127.0.0.1):8888/?token=64e73aaba8febd5539fae22201c7b7cea1b8578cc1413850
[I 08:01:55.465 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 08:01:55.466 NotebookApp]

Copy/paste this URL into your browser when you connect for the first time,
to login with a token:
http://(9c7db93b3678 or 127.0.0.1):8888/?token=64e73aaba8febd5539fae22201c7b7cea1b8578cc1413850

打开浏览器窗口,输入localhost:8888/?token=64e73aaba8febd5539fae22201c7b7cea1b8578cc1413850,可以看到一个Jupyter的界面。
jupyter

在里面可以编辑及运行python程序,或者使用终端操作:

bash
$ docker exec -it tensor /bin/bash
root@9c7db93b3678:/notebooks# ls
1_hello_tensorflow.ipynb  2_getting_started.ipynb  3_mnist_from_scratch.ipynb  BUILD  LICENSE
root@9c7db93b3678:/notebooks# python
python            python2           python2.7         python3           python3.5m
python-config     python2-config    python2.7-config  python3.5         python3m
root@9c7db93b3678:/notebooks# python
Python 2.7.12 (default, Dec  4 2017, 14:50:18)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.

关于Docker的Runtime

一个容器运行需要制定规范、Runtime、管理和定义工具、镜像仓库、运行OS等环节。容器的Runtime是容器运行时的一些规范,主要任务是和操作系统的kernel协作来提供容器的运行环境,由OCI(Open Container Initiative,由Google,Docker、CoreOS、IBM、微软、红帽等于2015年联合发起的组织)维护。主要包括容器的文件系统包(Filesystem Bundle),容器的运行和生存周期Runtime and Lifecycle),容器配置文件(Container Configuration file),以及Linux的运行和配置文件(Linux Runtime, Linux Container Configuration)等。目前Linux上最原始的容器Runtime是LXC,即Linux Container,最初Docker也是用LXC作为Runtime,后来Docker基于libcontainer开发了自己的Runtime,即runC。谷歌也基于Docker的Runtime发布了Kubernetes,后来CoreOS开发了独立的rkt作为运行容器的Runtime。
而与容器相对的就是虚拟机了,目前虚拟机的Runtime如runV,看名字就知道是要与runC分庭抗礼的。此外Intel也弄了一个Clear containers的Runtime,也可以对接容器。基于Hyper runV和Clear containers,Openstack又新起了一个Kata Containers,目前已经可以在snap商店看到了,才出来没多久,地址在这

利用Docker搭建私有云盘

安装

这里使用的是一个开源的云存储方案OwnCloud来搭建私有云盘。
首先可以搜一下Dockerhub中的镜像,docker search owncloud可以看到结果:

owncloud

其中第一个就是官方的镜像了,直接docker pull owncloud:8.1拉取就行。或者也可以直接docker run,本地没有它会去Dockerhub下载。

bash
docker run -d -p 80:80 owncloud:8.1

其中,-d表示后台运行,-p用来映射端口。也可以直接用-it前台打开tty直接操作。
这时候可以在浏览器中看到了,输入localhost就可以看到登陆界面,大致是下面的样子: owncloud

运行配置

其中数据保存在/var/www/html/data目录中,默认是使用SQLite用于数据存储,但对于较大的或者使用桌面客户端同步文件时,并不推荐SQLite,可以考虑最流行的MySQL。其他数据库需要外部安装。
在运行时可以使用-v选项来将本地磁盘挂载到容器中数据保存的位置,即/var/www/html/中。

-v /<mydatalocation>:/var/www/html

分的更细一点,可以添加三项,设置命令:

-v /<mydatalocation>/apps:/var/www/html/apps installed / modified apps
-v /<mydatalocation>/config:/var/www/html/config local configuration
-v /<mydatalocation>/data:/var/www/html/data the actual data of your ownCloud

数据库配置

外部数据库配置有几种方法,第一个是使用Owncloud自己提供的OCC工具(OwnCloud Console)来配置,使用docker exec执行:

bash
docker exec -u www-data some-owncloud php occ status

另外的就是用Docker的工具了,Docker Stack或者Docker Compose来配置。首先需要编辑一个yml配置文件,如stack.ymlcompose.yml,名字随便起,然后加入数据库配置:

yaml
# ownCloud with MariaDB/MySQL
#
# Access via "http://localhost:8080" (or "http://$(docker-machine ip):8080" if using docker-machine)
#
# During initial ownCloud setup, select "Storage & database" --> "Configure the database" --> "MySQL/MariaDB"
# Database user: root
# Database password: example
# Database name: pick any name
# Database host: replace "localhost" with "mysql"
version: '3.1'
services:
  owncloud:
    image: owncloud:8.1
    restart: always
    ports:
      - 8080:80
    volumes: 
      - "/home/newdee/Downloads/owncloud/:/var/www/html/"
  mysql:
    image: mysql:5.6
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: owncloud
      MYSQL_USER: first
      MYSQL_PASSWORD: 123456

最后运行docker stack deploy -c stack.yml owncloud (or docker-compose -f compose.yml up)即可。
此时可以发现有两个容器正在运行:

bash
 $ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
8499dc015bc8        owncloud:8.1        "/entrypoint.sh apac…"   15 minutes ago      Up 12 minutes       0.0.0.0:8080->80/tcp   owncloud_owncloud_1
6e145ebcca20        mysql:5.6           "docker-entrypoint.s…"   15 minutes ago      Up 12 minutes       3306/tcp               owncloud_mysql_1

然后在浏览器输入http://localhost:8080可以看到登陆界面,登录信息填yml文件中的信息就行。
owncloud

登陆成功就可以看到登陆界面了。然后就可以网页上传下载了,还可以生成分享链接。上传下载地址位于挂载的目录中。没有机子也可以去试试VPS,自己搭一个私有云盘用来平时备份下载。

owncloud