Docker的使用方法

1. 什么是Docker

Docker是一种软件虚拟化机制,可以在同一个操作系统内核之上实现文件系统、应用程序的隔离。每一个互相隔离的单元称为一个"容器(Container)"。
相比于VMWare、VirtualBox等虚拟机进行硬件虚拟化、并直接启动新的操作系统的方式,因为所有Docker容器都共享宿主机的内核,所以更加节省资源,即便普通PC也能同时运行许多个容器。这就容许软件部署从面向宿主机转变为面向容器进行。

Linux与生俱来的局限性是可执行文件与库之间的兼容性问题,因为每一个Linux发行版本都有自己固有的包系统。 Docker将应用程序或服务中的可执行状态的组合用容器捆绑在一起,再通过网络共享,使用Docker可以帮助Linux使用开发者和管理者大大缩短在系统构建与管理上所浪费的时间。与Github类似,用户也可以基于Docker Hub中的镜像创建并分享自己的镜像。
Docker提供专门创建并部署镜像的功能,如同Git中管理代码一样,Docker也提供了镜像版本管理的功能。Docker也提供镜像上传和下载功能,Docker还提供了多种API,帮助用户轻松实现自动化部署。

docker 究竟是什么?docker 是一个基于LXC (linux containers)的高级容器引擎。听起来是不是不知道在说什么?简单地说,docker 是一个轻量级的虚拟解决方案,或者说 —— 一个超轻量级的虚拟机。你一定理解虚拟机是什么,那么,你现在可以认为 docker 是一个秒级启动的虚拟机,可以轻易创建和删除,就这一点,是不是酷毙了。
 
我们会经常看到这个 docker 的图,它告诉我们,docker 是一种集装箱式的工作方式。正如我们会将各种不同的货物统一打包成一个个集装箱,进行标准的管理和运输,在 docker 的世界里,我们把应用和应用所依赖的运行环境打包成一个个 image,然后分发到任意支持 docker 的平台,就可以在这些平台运行我们的应用,提供服务。
那支持 docker 的平台有哪些?因为 docker 是基于 linux 的,在任意的 linux 发行版我们都可以原生地支持 docker,只要对应的内核版本大于 3.10 并且是 64bit,而在 Windows 和 Mac 中,我们可以通过 boot2docker 来运行 docker,这几乎意味着,所有的主流平台都支持 docker 的运行 —— 从此你不再需要为跨平台而苦恼。

当我们在一台 Linux 主机上安装完 Docker 之后,
我们的机器中就包含了本地主机Docker 主机
如果从网络层来划分,本地主机就代表你的电脑,而 Docker 主机就代表你运行的容器

这里写图片描述

在一个典型的 Linux 主机上安装 Docker 客户端,运行 Docker daemon ,并且在本地主机上直接运行一些容器。这就意味着你可以为 Docker 容器指定本地主机端口,例如 localhost:8000 或者 0.0.0.0:8376。

1.1 Docker vs VM

这里写图片描述
与虚拟化相比,Docker是一种更轻量化的方式,使用Docker不需要安装客户OS, Docker镜像只隔离并安装服务器运行所需要的程序与库,与主机共享OS资源,这样就大大减小了镜像的体积
Docker没有硬件虚拟化层,与虚拟机相比,其在内存访问、文件系统、网络速度上明显快很多

说起虚拟化,与 VM 的比较是离不开的,我们可以看看这张图:
vm 的理念是在宿主的系统之上,自己虚拟了一个硬件平台,然后运行一个不同的 OS。这意味着它要求很多的资源,在一台机器上,你最多就跑几个虚拟机吧。
 
docker依托于宿主机提供的内核,仅仅把一个不同的 linux 发行版本所需的特性打包成一个 image, 这样子当你运行一个 ubuntu 镜像,你会感觉就是在一个 ubuntu 的操作环境里,但实际调用的系统接口都是来源于宿主机。所以当运行一些内核相关的命令时,你就会发现一些端倪,比如 uname -a, 这时给出的信息肯定是宿主机的。
 
因为共用宿主机的内核,所以 docker 所需的资源也很少,性能开销很小,通常可以在秒内启动,有些已经可以做到毫秒内启动了。在一台机器上,你完全可能做到同时运行上千个 docker 的容器。
 
Docker设计理念
docker 的运行方式也让我们对 VM 的理念产生质疑,假如我们需要虚拟一个不同的运行环境,是否需要一个完全新的系统?其实我们要的只是运行一个应用所需的依赖环境,不是吗?
 
总的来说,docker 抛弃传统 VM 试图模拟完整机器的思路,本着“面向应用”的核心理念,以应用为单元进行”集装封箱”。

1.2 Docker vs LXC

LXC 是什么?LXC 就是 Linux Container(内核级虚拟化)。 LXC 也是一种轻量的虚拟技术,Linux 原生支持的容器。可以说 docker 就是基于 LXC 发展起来的,提供 LXC 的高级封装,发展标准的配置方法。
 
LXC 的定位是替代传统的虚拟机,侧重于提供一个个操作系统,如 Ubuntu、Debian等。Docker 是面向应用的,官方提倡一个容器即是一个应用,以应用为中心。所以,docker 还提供了统一的打包部署方案,即 Dockerfile, 还有版本控制,image 复用,远程仓库以供镜像共享等。
可以说,LXC 只是 Docker 的底层技术之一,而 Docker 已经在此之上发展出了一个生态系统,如果有另一种容器虚拟技术的话,也许 LXC 也只是配置文件里的 option 选项,libContainer 项目就是在做这样的事情。

1.3 为什么要使用Docker

Docker就是一个面向应用的容器,用来把程序的运行环境打包,构建统一的运行环境,从而能够在不同的平台同样使用我们针对这套应用所拥有的环境。
 
看到这里,你应该对 docker 在解决的问题有一些模糊的概念,我们不妨总结一下Docker 在解决什么问题:

  • 简化配置。在容器中开发完成后快速部署于各主流系统,解决了地狱依赖问题,再也没有了“在我电脑明明可以运行”的情况。
  • 机器资源利用率的提高,不需要为虚拟一个环境而耗费大量资源。
  • 改变了传统应用交付的方式,软件的开发和管理从部门间的装配和调试转换为部件的简单替换。
  • 软件的管理和共享从代码层次向应用层次上升。给了我们更多的选择自由性,使软件架构更加灵活。
     
    也许以后 docker 成为了新的软件管理模式,我们不会再看到开发人员为每个不同发行版本编写配置文件,处理复杂的系统依赖。无论我们需要什么服务,我们只需要安装 docker,然后 pull 一个镜像到本地就可以了。事实上,我们已经开始看到这种趋势了,毕竟 docker 作为开发和测试来说都太方便了。

2. 如何安装 Docker

Install Docker 18.3
ubuntu docker 的安装与配置

sudo apt-get remove docker docker-engine docker.io
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common

//add gpg-key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88

// set up the stable repository
sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

//查看可安装的版本
apt-cache madison docker-ce

sudo apt-get install docker-ce
sudo apt-get install docker-ce=<VERSION>

3. 如何使用 Docker

Docker Hub >> image >> container

  • Docker Hub: image镜像的仓库
  • container: image镜像运行的一个实例
  • 通常一个镜像由若干个layer组成,多个镜像包含相同层时,本地只存储一份

3.1 基本命令

docker --version
docker info
docker run hello-world
docker image ls
docker images
docker container ls --all

3.2 镜像(image)命令

拉取镜像
docker pull ubuntu:16.04
创建镜像

创建镜像的几种方式:

  1. 基于已有镜像的容器创建
  2. 基于本地模板导入
  3. 基于container/image 导入导出实现镜像共享
  4. 基于Dockerfile创建
1. 基于已有镜像的容器创建 (docker commit)

这种方式适用于,在已有的镜像中添加内容,比如添加依赖库、软件程序和代码等

把image启动,在container中添加相应的内容
docker commit -m "add a new user hualong" -a "hualong" 4adc8fc4490b myubuntu:16.04
-m 添加注释
-a 添加作者信息
跟上运行着的container的ID
最后添加制作镜像的名称和tag

# 比如在一个python镜像中。添加freetds-dev和unixodbc-dev这两个依赖,生成一个新的镜像
## 进入容器内部进行交互
docker run -it --name python docker.io/python:3.6.4 /bin/bash

apt-get install freetds-dev
apt-get install unixodbc-dev

安装完成后,ctrl+p+q退出容器
docker commit 39eaa5aa7332 python3.6.4-dev
2. 基于本地模板导入(docker import)

使用 docker import,直接从一个操作系统模板文件导入一个镜像
docker import命令使用说明


从 http://openvz.org/Download/templates/precreated 下载模版文件
然后使用以下命令 docker import导入
cat ubuntu-14.04-x86_64-minimal.tar.gz | docker import - ubuntu:14.04
3. 基于container/image 导入导出实现镜像共享

image的导出与导入

docker save  # 将指定镜像保存成 tar 归档文件
docker load  # 导入镜像存储文件到本地镜像库

docker save -o ubuntu_14.04.tar ubuntu:14
docker load < ubuntu_14.04.tar

container的导出与导入

docker export  #将指定镜像保存成 tar 归档文件

docker export 4adc8fc4490b(contarinerID/Name) > ubuntu16_running.tar
docker import ubuntu16_running.tar > test/ubuntu_test:16.04

两者的区别

  • 两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也更大
  • docker save保存的是镜像(image),docker export保存的是容器(container)
  • docker load用来载入镜像包,docker import用来载入容器包,但两者都会恢复为镜像
  • docker load不能对载入的镜像重命名,而docker import可以为镜像指定新名称
4. 基于Dockerfile创建

使用 docker build 命令来根据 Dockerfile 创建镜像

  • –build-arg=[] :设置镜像创建时的变量;
  • –tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签。

3.3 容器(container)命令

启动容器 (docker run)
docker run -it ubuntu:14.04 /bin/bash
# 利用ubuntu镜像创建一个容器, 在其中运行bash应用
进入容器(docker exec / attach)
# 连接到容器
docker attach contaionerID/Name  
>  首先container的状态不能是 `Exited`
>  当多个窗口同时用attach命令连到同一个容器的时候,所有窗口都会同步显示, 
>  有一个阻塞,其他都阻塞

# 在容器内直接执行任意命令
docker exec -it containerID/Name /bin/bash 

> -i,--interactive=true|false:打开标准输入接受用户输入命令
> -t,--tty=true|false:分配伪终端,默认为false;
> --privileged=true|false:是否给执行命令以高权限,默认为false
> -u,--user="":执行命令的用户名或ID

-it参数来保持标准输入打开,并且分配一个伪终端。通过exec命令对容器执行操作是最为推荐的方式

删除容器
# 删除处于终止或退出状态的容器
docker rm containerID/Name

> - -f,--force=false:是否强行终止并删除一个运行中的容器
> - -l,--link=false:删除容器的连接,但保留容器
> - -v,--volumes=false:删除容器挂载的数据卷

4. 生成镜像的原则

  • 精简镜像用途: 尽量让每个镜像的用途都比较集中、单一,避免构造大而复杂、多功能的镜像

  • 选用合适的基础镜像: 过大的基础镜像会造成生成臃肿的镜像

  • 提供足够清晰的命令注释和维护者信息: Dockerfile也是一种代码,需要考虑方便后续扩展和他人使用

  • 正确使用版本号: 使用明确的版本号信息,如1.0,2.0

  • 及时删除临时文件和缓存文件: 特别是在执行apt-get指令后,/var/cache/apt下面会缓存一些安装包

    所以 apt-get install 之后通常有 rm -rf /var/lib/apt/list/*

  • 减少镜像层数: 如果希望所生成镜像的层数尽量少,则要尽量合并指令,例如多个RUN指令可以合并为一条

  • 提高生成速度: 如合理使用缓存,减少内容目录下的文件,或使用.dockerignore文件指定等

  • 调整合理的指令顺序: 在开启缓存的情况下,内容不变的指令尽量放在前面,这样可以尽量复用

  • 减少外部源的干扰: 如果确实要从外部引入数据,需要指定持久的地址,并带有版本信息,让他人可以重复而不出错

  • docker中运行你的应用程序。

  • 运行你自己的容器。

  • 创建docker镜像。

  • 分享你的docker镜像。

5. docker在生产过程中的应用

  • High Availibity机制: HAProxy工具来代理容器访问,这样在容器出现故障时,可以快速切换到功能正常的容器
  • 合适的容器重启策略,来自动重启退出的容器

5.1 搭建私有docker仓库,维护内部镜像

可以通过官方提供的registry镜像来简单搭建一套本地私有仓库环境
docker run -d -p 5000:5000 -v /opt/data/registry:/tmp/registry registry
> 启动私有仓库服务,监听端口5000 本地镜像存放路径/opt/data/registry

## push
 docker tag ubuntu:14.04 10.0.2.2:5000/test
 docker push 10.0.2.2:5000/test

## search
  curl http://10.0.2.2:5000/v1/search

## add Hub to docker daemon
> DOCKER_OPTS="--insecure-registry 10.0.2.2:5000"
## pull
 docker pull 10.0.2.2:5000/test
## tag
 docker tag 10.0.2.2:5000/test ubuntu:14.04

5.2 Docker 数据管理

  • 生产环境中使用Docker的过程中,往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,这必然涉及容器的数据管理操作
  • 在生产环境中,除了使用数据卷或数据卷容器之外,定期将主机的本地数据进行备份,或者使用支持容错的存储系统,包括RAID或分布式文件系统如Ceph、GPFS、HDFS等

container数据管理有两种方式

  1. Data Volumes:容器内数据直接映射到本地主机环境
  2. Data Volume Containers:使用特定容器维护数据卷
Data Volumes

数据卷是一个可供容器使用的特殊目录,它将主机操作系统本地目录直接映射进容器,类似于Linux中的mount操作

  • data volumes 可以在容器之间共享和重用,使得容器间的数据传递变得高效方便
  • 对数据卷内数据的修改会立马生效,无论是容器内操作还是本地操作 (两者映射到了一起)
  • 对数据卷的更新不会影响镜像,解耦了应用和数据
  • data volumes会一直存在,直到没有容器使用,可以安全地卸载它
  • 本地目录的路径必须是绝对路径,如果目录不存在, Docker会自动创建。
docker run -d -P --name web \
 -v /src/webapp:/opt/webapp training/webapp python app.py

## 加载主机的/src/webapp目录到容器的/opt/webapp目录
## 用户可以将一些程序或数据放到本地目录中,然后在容器内运行和使用

#! Docker挂载数据卷的默认权限是读写(rw),用户也可以通过ro指定为只读
Data Volumes container

数据卷容器也是一个容器,但是它的目的是专门用来提供数据卷供其他容器挂载。

  • 使用 --volumes-from 指定要挂载哪个容器的 data volumes
  • 可以多次使用–volumes-from参数来从多个容器挂载多个数据卷
  • Data Volumes关联之后, 删除一个container数据卷还会保留,除非所有关联的container都被删除了

1. 实现多个container之间的 data volume共享

# 首先启动一个container (data_container), 并且在container中创建一个 data volume
docker run -it -v /dbdata --name data_container ubuntu


# 使用--volumes-from来挂载dbdata容器中的数据卷,
# 例如创建一个test1容器,并从data_container容器挂载数据卷:
 docker run -it --volumes-from data_container --name test1 ubuntu
 
 这样两个container 可以共享 data volumes:  /dbdata

2. 数据备份 / 恢复

> a. 启动一个container 作为 data volumes container
> b-1. 启动另一个container 用--volumes-from关联 data volume
> b-2. 在这个container中 将本地目录连接到 container另一个目录中
> b-3. 这样就建立了本地目录与 共享data valumes的联系,使用命令备份数据
> 
> c-1. 恢复:新启动一个container,用--volumes-from关联 data volume
> c-2. 在这个container中 将本地目录连接到 container另一个目录中
> c.3. 使用命令 恢复数据

docker run -it -v /dbdata --name data_container ubuntu

# 备份
docker run --volumes-from data_container \
-v $(pwd):/backup --name worker ubuntu tar cvf /backup/backup.tar /dbdata

# 恢复
docker run --volumes-from data_container \
-v $(pwd):/backup ubuntu:16.04 tar xvf /backup/backup.tar

5.3 端口映射 与 容器互联

要多个服务组件容器共同协作的情况,不仅需要数据互通,往往需要多个容器之间有能够互相访问到对方的服务,除了通过网络访问外,Docker还提供了两个很方便的功能来满足服务访问的基本需求.

  • 一个是允许映射容器内应用的服务端口到本地宿主主机
  • 另一个是互联机制实现多个容器间通过容器名来快速访问。本章将分别讲解这两个很实用的功能
1. container服务端口的映射
# 本地5000端口 映射到container 5000端口
docker run -d -p 5000:5000 training/webapp python app.py

# 标记可以绑定多个端口
docker run -d -p 5000:5000 -p 3000:80 training/webapp python app.py

# 映射到指定地址的指定端口
docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py

# 映射到指定地址的任意端口 
docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py

# 指定使用 udp端口
docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py 
2. 容器的互联 linking

容器的互联(linking)是一种让多个容器中应用进行快速交互的方式。
它会在源容器和接收容器之间创建连接关系,接收容器可以通过容器名快速访问到源容器,而不用指定具体的IP地址

link参数的格式为: --link name:alias
#其中name是要连接的容器名称,alias是这个连接的别名


docker run -it -d --name db_service ubuntu:16.04
docker run -it --link db_service:db_link --name test1 ubuntu:16.04

> 这相当于Docker在两个互联的容器之间创建了一个虚机通道,
> 而且不用映射它们的端口到宿主主机上。在启动test1容器的时候并没有使用-p和-P标记,
> 从而避免了暴露数据库服务端口到外部网络上

6. 如何将代码放进 Docker中

  1. 容器启动时:RUN git clone …
  2. 镜像构建时:COPY . /whatever
  3. 容器运行时:docker run -v $(pwd):/whatever/

生产环境(复制代码到容器)

在构建时,将代码放入容器中:
(1)启动速度块;
(2)一次构建,到处运行;(一致性、可移植)
(3)可快速回滚(快速切换到上一版本的镜像)

开发环境(使用绑定挂载)

在进行本地开发时,将代码挂载到容器中:
(1)便于调试。日志文件可以写入绑定挂载的目录中。
(2)立即生效。将代码绑定挂载到容器中,修改后可以立即生效;

「绑定挂载」带来的问题:

(1)容器中的进程可以修改、删除主机中绑定挂载的文件。功能强大,但是也存在安全隐患。
(2)绑定挂载暴露文件到容器,降低了容器的安全和隔离。

7. NVIDIA-Docker 可使用 GPU 的 DOCKER 容器

这里写图片描述

https://github.com/NVIDIA/nvidia-docker

容器将应用程序封装到隔离的虚拟环境中,以简化数据中心的部署。通过将所有应用程序依赖项 (例如二进制文件和库) 都包括在内,应用程序容器能在任何数据中心环境中无缝地运行。
 
Docker 是领先的容器平台,它现在可用于容器化 GPU 加速的应用程序。这意味着无需进行任何修改即可轻松容器化和隔离加速的应用程序,并将其部署到任何受支持的、可使用 GPU 的基础架构上。 管理和监控加速的数据中心将变得空前容易。

  • 可以将旧的加速计算应用程序容器化,并部署在较新的系统、内部环境或云中。
  • 可以将特定的 GPU 资源分配给容器,以获得更好的隔离效果和性能。
  • 可以轻松地跨不同的环境共享应用程序、协同工作和测试应用程序
     

nvidia-docker 设计理念
Docker® containers are often used to seamlessly deploy CPU-based applications on multiple machines. With this use case, containers are both hardware-agnostic and platform-agnostic. This is obviously not the case when using NVIDIA GPUs since it is using specialized hardware and it requires the installation of the NVIDIA driver. As a result, Docker Engine does not natively support NVIDIA GPUs with containers.
 
To solve this problem, one of the early solutions that emerged was to fully reinstall the NVIDIA driver inside the container and then pass the character devices corresponding to the NVIDIA GPUs (e.g. /dev/nvidia0) when starting the container. However, this solution was brittle: the version of the host driver had to exactly match driver version installed in the container. The Docker images could not be shared and had to be built locally on each machine, defeating one of the main advantages of Docker.
 
To make the Docker images portable while still leveraging NVIDIA GPUs, the container images must be agnostic(不可知)of the NVIDIA driver. This repository provides utilities to enable GPU support inside the container runtime. 这样只要你的电脑安装了NVIDIA显卡驱动,不管你的电脑装的什么显卡,在不同的平台和数据中心,只要使用这个容器,都能达到同样的效果。

Install NVIDIA-Docker

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

使用 NVIDIA-Docker

https://ngc.nvidia.com/
docker login nvcr.io
Username: $oauthtoken
Password: k7cqFTUvKKdiwGsPnWnyQFYGnlAlsCIRmlP67Qxa

docker pull nvcr.io/nvidia/caffe2:17.10
nvidia-docker run -it --rm –v local_dir:container_dir nvcr.io/nvidia/caffe2:<xx.xx>

nvic.io/nvidia  表示 NVIDIA container registry/registry space 
后面是container

-it 表示可以以 interactice 方式运行容器
--rm 当运行完成,delete container
-v  挂载文件  一般使用docker,会让docker的数据存在本地,所以需要本地和docker建立一个链接
-v local-dir:container-dir

CUDA Toolkit Container
所有的NGC Container images 都是基于CUDA platform (nvcr.io/nvidia/cuda)
The toolkit includes GPU-accelerated libraries, debugging and optimization tools, a C/C++ compiler and a runtime library to deploy your application.

使用 NVIDIA-Docker 搭建Digits环境

$ mkdir /home/username/data
$ mkdir /home/username/digits-jobs

nvidia-docker run --name digits -d -p 8888:5000 \
 -v /home/username/data:/data:ro
 -v /home/username/digits-jobs:/workspace/jobs nvcr.io/nvidia/digits:18.05
打开 http://localhost:8888 

5. 参考文献

https://docs.nvidia.com/ngc/ngc-user-guide/index.html

https://blog.csdn.net/jcjc918/article/details/46486655
https://www.nvidia.cn/object/docker-container-cn.html
NVIDIA-docker https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(version-2.0)#prerequisites
docker学习论坛 http://www.docker.org.cn/
docker-doc https://docs.docker.com/get-started/part2/#pull-and-run-the-image-from-the-remote-repository

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一銤阳光

希望分享的内容对你有帮助

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值