Pinvon's Blog

所见, 所闻, 所思, 所想

Docker从入门到实践-笔记

Docker简介

什么是Docker

传统虚拟机技术: 虚拟出一套硬件后, 在其上运行一个完整操作系统, 在该系统上再运行所需应用进程.

Docker: 容器内的应用进程直接运行在宿主的内核上, 容器内没有自己的内核, 也没有进行硬件虚拟, 比传统虚拟机更为轻便.

如图所示:

0.png

Docker的好处

更高效的利用系统资源: 不需要进行硬件虚拟及运行完整操作系统等额外开销.

更快速的启动时间: 秒级.

一致的运行环境: 提供了除内核外一致的运行时环境.

更轻松的迁移

更轻松的维护和扩展: Docker团队和许多开源项目团队一起维护了一大批高质量的官方镜像, 既可直接在生产环境使用, 又可以作为基础进一步定制.

基本概念

镜像

操作系统分为内核和用户空间, 对于Linux而言, 内核启动后会挂载root文件系统为其提供用户空间支持.

Docker镜像就相当于是一个root文件系统. 如官方镜像 ubuntu:16.04 就包含了完整的一套Ubuntu16.04最小系统的root文件系统.

Docker镜像就是一个特殊的文件系统, 提供了容器运行时所需的文件与配置参数.

容器

镜像和容器的关系, 就像是面向对象程序设计中的类和实例的关系一样. 镜像是静态的定义, 容器是镜像运行时的实体, 容器可以被创建, 启动, 停止, 删除, 暂停等.

仓库(Docker Registry)

镜像构建完成后, 可以很容易地在当前宿主机器上运行, 而如果需要在其他主机上使用该镜像, 就需要一个集中的存储, 分发镜像的服务, Docker Registry就是这样的服务.

一个Docker Registry中可以包含多个仓库(Repository), 每个仓库可包含多个标签(Tag), 每个标签对应一个镜像. 一般Repository对应一个软件, Tag对应该软件的版本.

我们可以通过 <Repository>:<Tag> 来指定具体使用该软件的哪个版本. 如果不给出标签, 将以 latest 作为默认标签. 如: ubuntu:16.04. 如果只写 ubuntu, 则被当成 ubuntu:latest.

Docker Registry公开服务是开放给用户使用, 允许用户管理镜像的Registry服务, 如Docker Hub.

国内访问这些服务可能会比较慢. 国内有些云服务商提供了针对Docker Hub的镜像服务, 这些镜像服务常被称为加速器, 如阿里云加速器, DaoCloud加速器.

除了公开服务, 也可以自己搭建私有服务.

安装Docker

以Ubuntu为例.

卸载旧版本

sudo apt-get remove docker docker-engine docker.io

安装

# 将官方Docker资源库的GPG密钥添加到系统
sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D

# 将Docker存储库添加到APT源
echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list

# 更新软件包数据库
sudo apt-get update

# 确保从Docker repo中安装
apt-cache policy docker-engine

sudo apt-get install -y docker-engine

# 开启docker服务
sudo service docker start

# 让docker服务开机自启动
sudo systemctl enable docker

# 如果要取消开机自动启动, 则输入
sudo systemctl disable docker

# 使用pip安装docker-compose
sudo pip install docker-compose

# 将当前用户加入docker组
sudo usermod -aG docker $USER

# 注销 重新登录

# 测试docker是否在运行
docker

使用镜像加速器

对于Ubuntu 16.04LTS, 在 /etc/docker/daemon.json 中写入如下内容(若文件不存在则新建):

{
  "registry-mirrors": [
    "https://registry.docker-cn.com"
  ]
}

重启服务:

sudo systemctl daemon-reload
sudo systemctl restart docker

检查加速器是否生效, 输入 docker info, 如果有如下内容, 说明生效(由于我用的是阿里云加速器, 所以显示的是阿里云的网址):

Registry Mirrors:
 https://obou6wyb.mirror.aliyuncs.com/

使用镜像

获取镜像

从Docker镜像仓库获取镜像的命令是 docker pull [选项] [Docker Registry地址[:端口号]/]仓库名[:标签].

Docker Registry地址[:端口号]中的地址一般是 <域名/IP>[:端口号], 默认地址是Docker Hub.

仓库名: <用户名>/<软件名>, 对于Docker Hub, 可以不给出用户名.

如: docker pull ubuntu:16.04.

当然, 如果配置了加速器, 则默认是从加速器下载, 而不是Docker Hub.

运行: docker run -it --rm ubuntu:16.04 bash. 再如: docker run -it --rm hyperledger/fabric-peer:latest bash.

-it: i表示交互式操作, t表示终端. -rm: 退出容器后将其删除. 如果不想删除, 这个参数可以不加, 最后在需要删除时使用命令docker rm. bash: 表示使用bash shell.

列出镜像

docker images.

体积与Docker Hub上显示的不同, 是因为Docker Hub显示的是压缩后的体积.

总体积并非所有镜像文件的总和, 因为Docker镜像是多层存储结构, 可以继承复用.

如果有镜像的仓库名和标签都是<none>, 说明这是虚悬镜像, 主要是因为新旧镜像同名, 旧镜像名称会被取消. 一般来说可以随意删除. 删除命令: docker image prune.

只列出部分镜像: docker images ls ubuntu.

删除本地镜像

docker image rmi [image-id]

image-id 是前几位, 而不需要所有都输入.

使用Dockerfile定制镜像

镜像的定制, 实际上是定制每一层所添加的配置和文件.

Dockerfile 是一个文本文件, 其内包含了一条条的指令, 每一条指令构建一层, 因此每一条指令的内容, 就是描述该层应当如何构建.

创建文件夹, 新建Dockerfile文件:

mkdir mynginx
cd mynginx
touch Dockerfile

内容为:

FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

定制镜像, 意思是以一个镜像为基础进行定制. FROM 就是指定基础镜像. 这在Dockerfile中是必备指令, 并且是第一条指令.

如果以 FROM scratch 开头, 说明不以任何镜像为基础.

RUN 指令用来执行命令行命令, 就像是直接在命令行中输入的命令一样.

Dockerfile会为每一条指令建立一层.

构建镜像: 在Dockerfile目录中执行 docker build -t nginx:v3 .. -t 参数指定镜像名称.

关于Dockerfile的具体内容, 有时间再继续学习.

操作容器

启动

docker run -it ubuntu:16.04 bash

后台运行

后台运行使用 -d 参数.

后台运行时, 如果有相关的输出信息, 并不会输出到宿主机器.

docker run -d ubuntu:17.10 /bin/sh -c "while true; do echo hello world; sleep 1; done"

# 查看输出信息
docker container logs

终止容器

docker container stop [container name]

# 终止状态的窗口可以用以下命令查看
docker container ls -a

# 处于终止状态的容器的启动
docker container start [container name]

# 重启
docker container restart [container name]

进入容器

docker exec -it [container name] bash

导入导出

导出:

docker container ls -a

# 记住要导出的容器id

docker export 7691a814370e > ubuntu.tar

导入:

cat ubuntu | docker import - test/ubuntu:v1.0

删除容器

# 删除一个处于终止状态的容器
docker container rm test

# 清理所有处于终止状态的容器
docker container ls -a
docker container prune

访问仓库

仓库(Repository)是集中存放镜像的地方.

注册服务器(Registry)是管理仓库的具体服务器. 每个服务器上有许多仓库, 每个仓库里有许多镜像.

如 dl.dockerpool.com/ubuntu, dl.dockerpool.com是注册服务器地址, ubuntu是仓库名.

Docker Hub

注册: 注册Docker账号

登录: docker login

退出: docker logout

查找镜像: docker search

拉取镜像: docker pull

如:

docker search centos

# 返回很多centos相关镜像

# 选择其中一个拉取
docker pull centos

推送:

docker username/ubuntu:17.10
docker search username

Compose项目

Docker Compose项目负责快速部署分布式应用. 其定位是"定义和运行多个Docker容器的应用".

在日常工作中, 一般需要多个容器相互配合来完成某项任务, 如要实现一个Web项目, 除了Web服务容器本身之外, 还要加上后端的数据库服务容器, 甚至还要负载均衡容器等.

Compose允许用户通过一个单独的 docker-compose.yml 模板文件来定义一组相关联的应用容器为一个项目.

Compose中有两个重要的概念:

  • 服务(service): 一个应用的容器, 实际上可以包括若干运行相同镜像的容器实例.
  • 项目(project): 由一组相关联的应用容器组成的一个完整业务单元, 在 docker-compose.yml 文件中定义.

Compose的默认管理对象是项目, 通过子命令对项目中的一组容器进行便捷的生命周期管理.

安装

直接到compose下载所需版本, 赋予执行操作.

mv docker-compose-xxx /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

卸载的话, 直接将该文件删除即可.

也可以通过pip安装.

pip install docker-compose
pip uninstall docker-compose # 卸载

命令说明

docker-compose -h

模板文件

默认的模板文件名为: docker-compose.yml, 格式为YAML格式.

version: "3"

services:
  webapp:
    image: examples/web
    ports:
      - "80:80"
    volumes:
      - "/data"

每个服务都必须通过 image 指令指定镜像, 或通过 build 指令(需要Dockerfile)等来自动构建生成镜像.

如果使用 build 指令, 在 Dockerfile 设置的选项将会自动被获取, 无需在 docker-compose.yml 中再次设置.

只讲一些常用的指令. 具体的, 可参考链接: https://yeasy.gitbooks.io/docker_practice/content/compose/compose_file.html

build

指定 Dockerfile 所在文件夹的路径. Compose 将会利用它自动构建这个镜像, 然后使用这个镜像.

version: '3'
services:
    webapp:
    build: ./dir

如果在构建镜像时需要使用参数, 则可以使用 context 指令:

version: '3'
services:

  webapp:
    build:
      context: ./dir
      dockerfile: Dockerfile-alternate
      args:
        buildno: 1

cap_add, cap_drop

指定容器的内核能力分配.

让容器拥有所有能力, 可以写成:

cap_add:
    - ALL

去掉 NET_ADMID 能力, 可以写成:

cap_drop:
    - NET_ADMIN

command

容器启动后默认执行的命令.

command: echo "hello world"

container_name

指定容器名称. 默认使用 项目名称_服务名称_序号 这种格式.

container_name: docker-web-container

devices

指定设备的映射关系:

devices:
  - "/dev/ttyUSB1:/dev/ttyUSB0"

depends_on

解决容器的依赖, 启动先后的问题. 先启动 redis & db, 再启动 web.

version: '3'

services:
  web:
    build: .
    depends_on:
      - db
      - redis

  redis:
    image: redis

  db:
    image: postgres

expose

暴露端口, 但不映射到宿主机器, 只被连接的服务访问. 仅可以指定内部端口为参数.

expose:
    - "3000"
    - "8000"

extra_hosts

指定额外的host名称映射信息.

extra_hosts:
 - "googledns:8.8.8.8"
 - "dockerhub:52.1.157.61"

在启动容器后, 容器的 /etc/hosts 中会添加以下两条条目:

8.8.8.8 googledns
52.1.157.61 dockerhub

image

指定镜像名称或镜像ID, 如果镜像在本地不存在, Compose 将会尝试拉取这个镜像.

image: ubuntu
image: orchardup/postgresql
image: a4bc65fd

ports

暴露端口信息. 格式为 宿主端口:容器端口, 也可以只指定容器端口, 宿主将会随机选择端口.

ports:
 - "3000"
 - "8000:8000"
 - "49100:22"
 - "127.0.0.1:8001:8001"

volumes

数据卷所挂载路径设置. 可以设置宿主机器路径(host:container)或加上访问模式(host:container:ro).

在指令中路径支持相对路径.

volumes:
 - /var/lib/mysql
 - cache/:/tmp/cache
 - ~/configs:/etc/configs/:ro

Comments

使用 Disqus 评论
comments powered by Disqus