Wave Spread...

从零开始的 Docker 使用教程

分类:Linux 评论: 0

Docker 是一个开源的应用容器引擎,基于 Go 语言开发 遵从 Apache 2.0 协议开源。

Docker 可以让用户打包应用以及依赖到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。

Docker 起源于 2010 年创业的一家叫作 dotCloud 的美国公司,dotCloud 早期是基于LXC技术的 PaaS 平台,它的理念是提供跨底层 IaaS 云、支持多种开发语言的开发云平台。但随着越来越多的公有云服务商进入,dotCloud 的理念很难依靠一家公司专有的技术实现。于是 dotCloud 的创始人在 LXC 的基础上,对容器技术进行了简化和标准化,命名为 Docker。

2013年3月,因 PaaS 市场发展缓慢,创始人 Solomon Hykes 决定放手一搏,将 Docker 项目开源同时推出了开放容器项目(OCP),Docker 和 Docker 开源社区随后迅速火起来。

2013 年 10 月 29 日,dotCloud 公司更名为 Docker 公司。目前,Docker已经成为发展最快的容器技术。

Docker 将软件所需的依赖及程序本体构建为一个独立镜像,可以在任何部署了 Docker 的 Linux 服务器上运行,减轻了运维人员的部署难度及跨系统的依赖问题。

容器与虚拟化

容器与虚拟化不同,容器使用完全沙箱机制,容器与容器相互之间不会有任何影响,更重要的是容器的性能开销极低。简单可以理解为容器是在隔离的环境运行的一个进程,如果进程被停止,容器就会销毁。

而虚拟化则需要一定的硬件支持,比如 KVM 虚拟化只能基于 Linux 内核(对版本有一定要求)进行虚拟化。并且虚拟化是完整虚拟化,会虚拟化出完整的一套系统,因此启动虚拟机需要走一遍完整的系统启动流程,消耗的时间比较久(相对于容器来说)。

容器的特性

容器的发展

UNIX Chroot(change root,切换根目录)这项功能将Root目录及其它子目录变更至文件系统内的新位置,且只接受特定进程的访问,即可构建一个简易的子系统。其设计目的在于为每个进程提供一套隔离化磁盘空间。1982 年其被添加至BSD。

FreeBSD Jails 与 Chroot 的定位类似,不过其中包含有进程沙箱机制以对文件系统、用户及网络等资源进行隔离。通过这种方式,它能够为每个 Jail、定制化软件安装包乃至配置方案等提供一个对应的IP地址。Jails 技术为 FreeBSD 系统提供了一种简单的安全隔离机制。它的不足在于这种简单性的隔离也同时会影响 Jails 中应用访问系统资源的灵活性。

Solaris Zone 技术为应用程序创建了虚拟的一层,让应用在隔离的 Zone (空间)中运行,并实现有效的资源管理。每一个 Zone 拥有自己的文件系统,进程空间,防火墙,网络配置等。Solaris Zone 技术真正的引入了容器资源管理的概念。在应用部署的时候为 Zone 配置一定的资源,在运行中可以根据 Zone 的负载动态修改这个资源限制并且是实时生效的,在其他Zone不需要资源的时候,资源会自动切换给需要的资源的Zone,这种切换是即时的不需要人工干预的,最大化资源的利用率,在必要的情况下,也可以为单个 Zone 隔离一定的资源。

LXC (Linux Containers,Linux 容器),其通过 cgroups 以及 Linux Namespaces 实现。也是第一套完整的 Linux 容器管理实现方案。在 LXC 出现之前,Linux 上已经有了类似 Linux-Vserver 、OpenVZ 和 FreeVPS。虽然这些技术都已经成熟,但是这些解决方案还没有将容器支持集成到主流 Linux 内核。相较于其它容器技术,LXC 能够在无需任何额外补丁的前提下运行在原版 Linux 内核之上。目前 LXC 项目由 Canonical 有限公司负责赞助及托管。

Docker 项目最初是由一家名为 DotCloud 的平台即服务厂商所打造,其后该公司更名为Docker。Docker在起步阶段使用 LXC,而后利用自己的 Libcontainer 库将其替换下来。与其它容器平台不同,Docker引入了一整套与容器管理相关的生态系统。其中包括一套高效的分层式容器镜像模型、一套全局及本地容器注册表、一个精简化REST API以及一套命令行界面等等。

Docker 入门

安装 Docker

本文环境为 CentOS 7 ,部署 Docker 需要先安装 EPEL 源。

# yum install epel-release -y

从清华源获取 REPO 文件

# wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo

替换源地址为国内源(大陆使用可提速及提高稳定性)

# sed -i 's#download.docker.com#mirrors.tuna.tsinghua.edu.cn/docker-ce#g' /etc/yum.repos.d/docker-ce.repo

安装 Docker CE (社区版)

# yum install docker-ce -y

优化镜像拉取地址

# cat >> /etc/docker/daemon.json <<'EOF'
{
  "registry-mirrors": ["https://registry.docker-cn.com"]
}
EOF

官方部署方法

配置依赖

$ sudo yum install -y yum-utils \
  device-mapper-persistent-data \
  lvm2

添加仓库

$ sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

其他选项

test 为测试分支,edge 为先锋分支(最新特性)。

$ sudo yum-config-manager --enable docker-ce-edge
$ sudo yum-config-manager --enable docker-ce-test

安装社区版

$ sudo yum install docker-ce

小贴士:仅推荐开发及测试环境使用 edge 及 test 分支。

Docker 命令

执行 docker 命令前需要将 docker 启动,否则会报错,因为 docker 也是一个标准的 C/S 架构。

# systemctl enable docker
# systemctl start docker

基础命令

检查 Docker 版本信息,会列出引擎的详细信息。

[root@docker01 ~]# docker version
Client:
 Version:           18.09.0
 API version:       1.39
 Go version:        go1.10.4
 Git commit:        4d60db4
 Built:             Wed Nov  7 00:48:22 2018
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.0
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.4
  Git commit:       4d60db4
  Built:            Wed Nov  7 00:19:08 2018
  OS/Arch:          linux/amd64
  Experimental:     false

检查 Docker 信息

[root@docker01 ~]# docker info
Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 4
Server Version: 18.09.0
Storage Driver: overlay2
 Backing Filesystem: xfs
 Supports d_type: true
 Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 Volume: local
 Network: bridge host macvlan null overlay
 Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: c4446665cb9c30056f4998ed953e6d4ff22c7c39
runc version: 4fc53a81fb7c994640722ac585fa9ca548971871
init version: fec3683
Security Options:
 seccomp
  Profile: default
Kernel Version: 3.10.0-862.14.4.el7.x86_64
Operating System: CentOS Linux 7 (Core)
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 1.936GiB
Name: docker01
ID: NIDN:RIAL:XLUR:DUQP:FQSQ:BNBI:KHXJ:5ELK:3DA6:NHN4:2AZC:66AI
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false
Product License: Community Engine

小贴士:此命令会展示出 docker 详细的信息,包括镜像数量及启动的容器信息等,因此一般用于监控使用。

镜像相关命令

# docker image search    检索镜像
# docker image pull      拉取镜像
# docker image ls        镜像列表
# docker image save      导出镜像
# docker image load      导入镜像
# docker image rm        删除镜像
# docker image inspect   镜像信息
# docker image build     构建镜像

容器相关命令

# docker container run             运行容器
# docker container ps              容器列表
# docker container exec            进入容器
# docker container stop            停止容器
# docker container kill            杀死容器
# docker container start           启动容器
# docker container rm              删除容器
# docker container inspect         容器信息

Docker 实例

拉取一个镜像

# docker image pull centos:6.9

使用此命令即可从仓库拉取某个版本的 centos 镜像,若省略冒号及后面的版本号则默认拉取最新版 latest 。

拉取一个 NGINX 镜像

# docker image pull nginx

启动第一个容器

# docker run -d -p 80:80 nginx

小贴士: -d 放在后台 -p 端口映射,冒号分割外部内部端口,最后指定镜像的名。

容器的镜像管理

# docker search IMAGE_NAME

小贴士:IMAGE_NAME 替换为需要搜索的镜像名,选择镜像的原则,有官方优先官方,其次考虑星星(点赞)多的。

已存在的镜像列表

# docker image list

或者可以使用(推荐)

# docker images

删除已存在的镜像

# docker image rm

或者可以使用(推荐)

# docker rmi

导出本地的镜像

# docker image save centos > docker_centos.tar.gz

小贴士:docker image save 可以简写为 docker save

导入本地镜像

# docker image load -i docker_centos.tar.gz

容器运行参数

# docker container run -it --name centos6 centos:6.9 /bin/bash

小贴士: -it 分配交互式终端,--name 指定容器名字,/bin/bash 指定命令解析器覆盖初始命令,部分镜像的基础镜像为精简镜像,因此请使用 /bin/sh

docker run 命令等同于创建容器实例并启动(docker create + docker start)

停止容器

# docker container stop CONTAINER_ID

杀死容器(强制)

# docker container kill CONTAINER_ID

容器列表

# docker container ps

小贴士:在此容器系列的命令中,中间的 container 可以省略,之后的全部命令会默认省略 container。此命令仅会显示存活的容器,添加-a参数即可显示全部的容器(包括已经退出的容器)。

即:

# docker ps -a

小贴士:其他有实际作用的参数还有 -q 仅显示容器 ID。

进入容器(大部分情况下为了排错)

# docker exec -it CONTAINER_ID /bin/bash

小贴士:使用 -it 分配交互式终端,CONTAINER_ID 可以使用 ID 或者 NAME,最后指定命令解释器。

# docker attach CONTAINER_ID

小贴士:此命令会共享同一个终端,因此不推荐使用。

删除容器

# docker rm -f CONTAINER_ID

小贴士:-f 参数为 force 为强制删除,可以移除失去响应的容器。

删除全部容器

# docker rm -f `docker ps -a -q`

总结:容器内的第一个进程必须一直处于前台运行的状态(必须 HANG 住),否则这个容器执行完毕命令就会处于退出状态(瞬间完成并退出)!

容器的网络访问

# docker container run -d -p 80:80 nginx

小贴士:容器的网络是建立在容器内部的,类似于沙箱,因此容器想对外开放端口需要对外进行映射,映射使用的是 NAT (iptables)方式,-P 为随机映射。

容器的数据卷管理

# docker container run -d -p 80:80 -v /opt/html:/var/www/html nginx

数据卷(文件或目录)

    -v /data
    -v src(宿主机的目录):dst(容器的目录)

数据卷容器

    --volumes-from

将容器保存为本地镜像

# docker commit CONTAINER_ID/CONTAINER_NAME   CONTAINER_NEW_NAME[:VERSION]

例子

1)基于容器制作镜像

# docker run -it centos:6.9

2)进入容器进行操作

yum install httpd
yum install openssh-server
/etc/init.d/sshd start

cat >> init.sh <<'EOF'
#!/bin/bash
/etc/init.d/httpd start
/usr/sbin/sshd -D
EOF

chmod +x /init.sh

3)查看容器的ID

# docker container ls -a

4)将容器提交为镜像

# docker commit CONTAINER_ID centos6-ssh-httpd:v1

5)测试镜像功能

扩展

说到 SystemD ,这个套件已经成为主流 Linux 发行版(比如 CentOS 7、Ubuntu 14+)默认的服务管理,取代了传统的 SystemV 服务管理。SystemD 维护系统服务程序,它需要特权去会访问 Linux 内核。而容器并不是一个完整的操作系统,只有一个文件系统,而且默认启动只是普通用户这样的权限访问 Linux 内核,也就是没有特权,所以自然就用不了!

因此,请遵守容器设计原则,一个容器里运行一个前台服务!

以特权模式运行容器即可解决此问题。

创建容器:

# docker run -d -name centos7 --privileged=true centos /usr/sbin/init

进入容器:

# docker exec -it centos /bin/bash

即可使用 systemD 启动服务

# yum install chrony
# systemctl start chronyd

Docker 构建镜像

Dockerfile 主要组成部分:

    FROM:centos:6.9    基础镜像信息        
    RUN yum install openssh-server -y    镜像操作指令
    CMD ["/bin/bash"]    容器启动执行指令

Dockerfile 常用指令:

    FROM 指定基础镜像
    MAINTAINER 指定维护者信息,可选
    RUN 在命令前面加上RUN即可
    ADD COPY文件,会自动解压
    WORKDIR 设置当前工作目录
    VOLUME 设置卷,挂载主机目录
    EXPOSE 指定对外的端口(-P 随机端口)
    CMD 指定容器启动后的要干的事情(可被替换)

Dockerfile 其他指令:

    COPY        复制文件
    ENV         环境变量
    ENTRYPOINT  容器启动后执行的命令(无法被替换,启容器的时候指定的命令,会被当成参数)

Docker 镜像层级

容器的镜像并不是一个单纯的文件而是一个多层覆盖后的层级文件,如图例所示。

Docker 自建镜像仓库

因此众所周知的原因,官方的仓库在中国大陆下载速度很慢甚至可能失败。并且企业及个人可能有打包完的自建镜像,因此需要自建仓库进行托管,不仅可以提高下载速度还能给企业或个人提供一个私人仓库。

搭建普通的仓库(无验证)

启动一个名为 registry 镜像

# docker run -d -p 5000:5000 --restart=always --name registry -v /opt/myregistry:/var/lib/registry  registry
# docker pull busybox
10.0.0.11:5000/centos6-sshd:v3
# vi /etc/docker/daemon.json
{
  "registry-mirrors": ["https://registry.docker-cn.com"],
  "insecure-registries": ["10.0.0.11:5000"]
}
# systemctl restart docker
docker push 10.0.0.11:5000/centos6-sshd:v3

带认证的仓库

# yum install httpd-tools -y
# mkdir /opt/registry-var/auth/ -p
# htpasswd  -Bbn kane material  >> /opt/registry-var/auth/htpasswd
# docker run -d -p 5000:5000 --restart=always --name registry -v /opt/registry-var/auth/:/auth/ -v /opt/myregistry:/var/lib/registry -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd registry 

参考链接

回复