01 初识 Docker

1.1 What is Docker

1.1.1 官网首页

https://www.docker.com/

Debug your app, not your environment

Securely build, share and run any application, anywhere

1.1.2 Docs

https://docs.docker.com/get-started/

Docker is a platform for developers and sysadmins to develop, deploy, and run applications with containers. The use of Linux containers to deploy applications is called containerization. Containers are not new, but their use for easily deploying applications is.

Docker 是供开发人员和系统管理员使用容器构建,共享和运行应用程序的平台。 使用容器部署应用程序称为容器化。 容器不是新的,但用于轻松部署应用程序的容器却是新的。

1.1.3 不理解,我太难了

不妨从一个需求开始 :开发好了一个项目 study,部署上线

  • 远古时代

    问题: 成本高、部署慢、浪费资源、硬件限制、不利于迁移扩展
  • 虚拟化时代
    hypervisor:虚拟化技术

    优点 :相对利用好资源,相对容易扩展等。
    缺点 :虚拟机太重了,一上来占用较多物理资源,移植性差,资源利用率低等。
  • 容器时代

1.1.4 再次理解 Docker

Docker is a platform for developers and sysadmins to build, share, and run applications with containers. The use of containers to deploy applications is called containerization. Containers are not new, but their use for easily deploying applications is.

Docker 是供开发人员和系统管理员使用容器构建,共享和运行应用程序的平台。 使用容器部署应用程序称为容器化。 容器不是新的,但用于轻松部署应用程序的容器却是新的。

发现还是比较容易理解的,但是这里有一句“Containers are not new”,也就是容器化技术很早就 出现了,比如常见的容器化技术有 OpenVZ 等。

1.1.5 Docker 的优势和应用场景

  1. 有助于微服务的落地和部署
  2. 充分利用物理机资源,同时能够整合服务器资源
  3. 提高开发效率,测试效率,部署效率,有利于 DevOps 的落地,CI/CD
  4. 云原生落地,应用更好地迁移 …

1.2 What is Image and Container?

docker engine —》 jvm

image —》 class 文件

container —》 Java 对象

1.2.1 What is Image?

Why is docker?-> https://www.docker.com/resources/what-container

A Docker container image is a lightweight, standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries and settings.

Docker 容器映像是轻巧的,独立的,可执行的软件软件包,其中包含运行应用程序所需的一切:代码,运行时,系统工具,系统库和设置。

1.2.2 What is Container?

Why is docker?-> https://www.docker.com/resources/what-container

A container is a standard unit of software that packages up code and all its dependencies so the application runs quickly and reliably from one computing environment to another.

容器是打包代码及其所有依赖项的软件的标准单元,因此应用程序可以从一个计算环境快速可靠地运行到另一个计算环境。

1.2.3 Relation between image and container

Container images become containers at runtime and in the case of Docker containers - images become containers when they run on Docker Engine.

容器映像在运行时会成为容器,对于 Docker 容器而言-映像在 Docker Engine 上运行时会成为容器。

1.2.4 View from Docs

从帮助文档的角度看 docker 官网->Resources->Docs->Get started->Quickstart->Orientation and setup->Images and containers

Fundamentally, a container is nothing but a running process, with some added encapsulation features applied to it in order to keep it isolated from the host and from other containers. One of the most important aspects of container isolation is that each container interacts with its own, private filesystem; this filesystem is provided by a Docker image. An image includes everything needed to run an application — the code or binary, runtimes, dependencies, and any other filesystem objects required.

从根本上说,一个容器不过是一个正在运行的进程,并对其应用了一些附加的封装功能,以使其与主机和其他容器隔离。 容器隔离的最重要方面之一是每个容器都与自己的私有文件系统进行交互。 该文件系统由 Docker 映像提供。 映像包括运行应用程序所需的所有内容-代码或二进制文件,运行时,依赖项以及所需的任何其他文件系统对象。

1.3 Containers and virtual machines

从帮助文档的角度看 docker 官网->Resources->Docs->Get started->Quickstart->Orientation and setup->Containers and virtual machines

A container runs natively on Linux and shares the kernel of the host machine with other containers. It runs a discrete process, taking no more memory than any other executable, making it lightweight.

By contrast, a virtual machine (VM) runs a full-blown “guest” operating system with virtual access to host resources through a hypervisor. In general, VMs incur a lot of overhead beyond what is being consumed by your application logic.

容器在 Linux 上本地运行,并与其他容器共享主机的内核。 它运行一个离散进程,不占用任何其他可执行文件更多的内存,从而使其轻巧。

相比之下,虚拟机(VM)运行成熟的“来宾”操作系统,并通过虚拟机管理程序对主机资源进行虚拟访问。 通常,VM 会产生大量开销,超出了应用程序逻辑所消耗的开销。

1.4 Docker Engine and Architecture

https://docs.docker.com/engine/docker-overview/

1.4.1 Docker Engine

Docker Engine is a client-server application with these major components:

  • A server which is a type of long-running program called a daemon process (the dockerd command).
  • A REST API which specifies interfaces that programs can use to talk to the daemon and instruct it what to do.
  • A command line interface (CLI) client (the docker command).

Docker Engine 是具有这些主要组件的客户端-服务器应用程序:

  • 一种长期运行的程序,称为守护程序进程(dockerd 命令)的服务。
  • REST API,它指定程序可以用来与守护程序进行通信并指示其操作的接口。
  • 命令行界面(CLI)客户端(docker 命令)。

1.4.2 Docker Architecture

Docker uses a client-server architecture. The Docker client talks to the Docker daemon, which does the heavy lifting of building, running, and distributing your Docker containers. The Docker client and daemon can run on the same system, or you can connect a Docker client to a remote Docker daemon. The Docker client and daemon communicate using a REST API, over UNIX sockets or a network interface.

Docker 使用客户端-服务器架构。 Docker 客户端与 Docker 守护程序进行对话,该守护程序完成了构建,运行和分发 Docker 容器的繁重工作。 Docker 客户端和守护程序可以在同一系统上运行,也可以将 Docker 客户端连接到远程 Docker 守护程序。 Docker 客户端和守护程序在 UNIX 套接字或网络接口上使用 REST API 进行通信。

1.5 Install

见附件

02 Image and Container

2.1 Image

2.1.1 官方 image

https://github.com/docker-library

mysql

https://github.com/docker-library/mysql/blob/master/5.7/Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
FROM debian:stretch-slim

# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added
RUN groupadd -r mysql && useradd -r -g mysql mysql

RUN apt-get update && apt-get install -y --no-install-recommends gnupg dirmngr && rm -rf /var/lib/apt/lists/*

# add gosu for easy step-down from root
ENV GOSU_VERSION 1.7
RUN set -x \
&& apt-get update && apt-get install -y --no-install-recommends ca-certificates wget && rm -rf /var/lib/apt/lists/* \
&& wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture)" \
&& wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture).asc" \
&& export GNUPGHOME="$(mktemp -d)" \
&& gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \
&& gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \
&& gpgconf --kill all \
&& rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc \
&& chmod +x /usr/local/bin/gosu \
&& gosu nobody true \
&& apt-get purge -y --auto-remove ca-certificates wget

RUN mkdir /docker-entrypoint-initdb.d

RUN apt-get update && apt-get install -y --no-install-recommends \
# for MYSQL_RANDOM_ROOT_PASSWORD
pwgen \
# for mysql_ssl_rsa_setup
openssl \
# FATAL ERROR: please install the following Perl modules before executing /usr/local/mysql/scripts/mysql_install_db:
# File::Basename
# File::Copy
# Sys::Hostname
# Data::Dumper
perl \
&& rm -rf /var/lib/apt/lists/*

RUN set -ex; \
# gpg: key 5072E1F5: public key "MySQL Release Engineering <mysql-build@oss.oracle.com>" imported
key='A4A9406876FCBD3C456770C88C718D3B5072E1F5'; \
export GNUPGHOME="$(mktemp -d)"; \
gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \
gpg --batch --export "$key" > /etc/apt/trusted.gpg.d/mysql.gpg; \
gpgconf --kill all; \
rm -rf "$GNUPGHOME"; \
apt-key list > /dev/null

ENV MYSQL_MAJOR 5.7
ENV MYSQL_VERSION 5.7.28-1debian9

RUN echo "deb http://repo.mysql.com/apt/debian/ stretch mysql-${MYSQL_MAJOR}" > /etc/apt/sources.list.d/mysql.list

# the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql)
# also, we set debconf keys to make APT a little quieter
RUN { \
echo mysql-community-server mysql-community-server/data-dir select ''; \
echo mysql-community-server mysql-community-server/root-pass password ''; \
echo mysql-community-server mysql-community-server/re-root-pass password ''; \
echo mysql-community-server mysql-community-server/remove-test-db select false; \
} | debconf-set-selections \
&& apt-get update && apt-get install -y mysql-server="${MYSQL_VERSION}" && rm -rf /var/lib/apt/lists/* \
&& rm -rf /var/lib/mysql && mkdir -p /var/lib/mysql /var/run/mysqld \
&& chown -R mysql:mysql /var/lib/mysql /var/run/mysqld \
# ensure that /var/run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime
&& chmod 777 /var/run/mysqld \
# comment out a few problematic configuration values
&& find /etc/mysql/ -name '*.cnf' -print0 \
| xargs -0 grep -lZE '^(bind-address|log)' \
| xargs -rt -0 sed -Ei 's/^(bind-address|log)/#&/' \
# don't reverse lookup hostnames, they are usually another container
&& echo '[mysqld]\nskip-host-cache\nskip-name-resolve' > /etc/mysql/conf.d/docker.cnf

VOLUME /var/lib/mysql

COPY docker-entrypoint.sh /usr/local/bin/
RUN ln -s usr/local/bin/docker-entrypoint.sh /entrypoint.sh # backwards compat
ENTRYPOINT ["docker-entrypoint.sh"]

EXPOSE 3306 33060
CMD ["mysqld"]

2.1.2 Dockerfile

2.1.2.1 FROM

指定基础镜像,比如 FROM ubuntu:14.04

1
FROM ubuntu:14.04

2.1.2.2 RUN

在镜像内部执行一些命令,比如安装软件,配置环境等,换行可以使用””

1
RUN groupadd -r mysql && useradd -r -g mysql mysql

2.1.2.3 ENV

设置变量的值,ENV MYSQL_MAJOR 5.7,可以通过 docker run —e key=value 修改,后面可以直接使 用${MYSQL_MAJOR}

1
ENV MYSQL_MAJOR 5.7

2.1.2.4 LABEL

设置镜像标签

1
2
LABEL email="732060461@qq.com"
LABEL name="kieran"

2.1.2.5 VOLUME

指定数据的挂在目录

1
VOLUME /var/lib/mysql

2.1.2.6 COPY

将主机的文件复制到镜像内,如果目录不存在,会自动创建所需要的目录,注意只是复制,不会提取和 解压

1
COPY docker-entrypoint.sh /usr/local/bin/

2.1.2.7 ADD

将主机的文件复制到镜像内,和 COPY 类似,只是 ADD 会对压缩文件提取和解压

1
ADD application.yml /etc/kieran/

2.1.2.8 WORKDIR

指定镜像的工作目录,之后的命令都是基于此目录工作,若不存在则创建

1
2
3
WORKDIR /usr/local
WORKDIR tomcat
RUN touch test.txt

会在/usr/local/tomcat 下创建 test.txt 文件

1
2
WORKDIR /root
ADD app.yml test/

会在/root/test 下多出一个 app.yml 文件

2.1.2.9 CMD

容器启动的时候默认会执行的命令,若有多个 CMD 命令,则最后一个生效

1
2
3
CMD ["mysqld"]

CMD mysqld

2.1.2.10 ENTRYPOINT

和 CMD 的使用类似

1
ENTRYPOINT ["docker-entrypoint.sh"]

和 CMD 的不同:

docker run 执行时,会覆盖 CMD 的命令,而 ENTRYPOINT 不会

2.1.2.11 EXPOSE

指定镜像要暴露的端口,启动镜像时,可以使用-p 将该端口映射给宿主机

1
EXPOSE 3306

2.1.3 Dockerfile 实战 Spring Boot 项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
(1)创建一个Spring Boot项目

(2)写一个controller
@RestController
public class DockerController {
@GetMapping("/dockerfile")
@ResponseBody String dockerfile() {
return "hello docker" ;
}
}

(3)mvn clean package打成一个jar包
在target下找到"dockerfile-demo-0.0.1-SNAPSHOT.jar"

(4)在docker环境中新建一个目录"first-dockerfile"

(5)上传"dockerfile-demo-0.0.1-SNAPSHOT.jar"到该目录下,并且在此目录创建Dockerfile

(6)创建Dockerfile文件,编写内容
FROM openjdk:8
MAINTAINER kieran
LABEL name="dockerfile-demo" version="1.0" author="kieran"
COPY dockerfile-demo-0.0.1-SNAPSHOT.jar dockerfile-image.jar
CMD ["java","-jar","dockerfile-image.jar"]

(7)基于Dockerfile构建镜像
docker build -t test-docker-image .

(8)基于image创建container
docker run -d --name user01 -p 6666:8080 test-docker-image

(9)查看启动日志docker logs user01

(10)宿主机上访问
curl localhost:6666/dockerfile hello docker

(11)还可以再次启动一个
docker run -d --name user02 -p 8081:8080 test-docker-image

2.1.4 镜像仓库

2.1.4.1 docker hub

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(1)在docker机器上登录
docker login

(2)输入用户名和密码

(3) 推送,[注意镜像名称要和docker id一致,不然push不成功]
docker push xxx/test-docker-image

(4)给image重命名,并删除掉原来的
docker tag test-docker-image xxx/test-docker-image
docker rmi -f test-docker-image

(5)再次推送,刷新hub.docker.com后台,发现成功

(6)别人下载,并且运行
docker pull xxx/test-docker-image
docker run -d --name user01 -p 6661:8080 xxx/test-docker-image

2.1.4.2 阿里云 docker hub

阿里云 docker 仓库

https://cr.console.aliyun.com/cn-hangzhou/instances/repositories

参考手册

https://cr.console.aliyun.com/repository/cn-hangzhou/kieran2019/test/details

2.1.4.3 搭建自己的 Docker Harbor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(1)访问github上的harbor项目
https://github.com/goharbor/harbor

(2)下载版本,比如1.7.1 https://github.com/goharbor/harbor/releases

(3)找一台安装了docker-compose[见附件],上传并解压
tar -zxvf xxx.tar.gz

(4)进入到harbor目录 修改harbor.cfg文件,主要是ip地址的修改成当前机器的ip地址 同时也可以看到Harbor的密码,默认是Harbor12345

(5)安装harbor,需要一些时间
sh install.sh

(6)浏览器访问,比如39.108.121.24,输入用户名和密码即可

2.1.5 Image 常见操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(1)查看本地image列表
docker images
docker image ls

(2)获取远端镜像
docker pull

(3)删除镜像[注意此镜像如果正在使用,或者有关联的镜像,则需要先处理完]
docker image rm imageid
docker rmi -f imageid
docker rmi -f $(docker image ls) 删除所有镜像

(4)运行镜像
docker run image

(5)发布镜像
docker push

2.2 Container

既然 container 是由 image 运行起来的,那么是否可以理解为 container 和 image 有某种关系?

其实可以理解为 container 只是基于 image 之后的 layer 而已,也就是可以通过 docker run image 创建出一个 container 出来。

2.2.1 container 到 image

既然 container 是基于 image 之上的,想想是否能够由一个 container 反推出 image 呢? 肯定是可以的,比如通过 docker run 运行起一个 container 出来,这时候对 container 对一些修 改,然后再生成一个新的 image,这时候 image 的由来就不仅仅只能通过 Dockerfile 咯。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
(1)拉取一个centos image
docker pull centos

(2)根据centos镜像创建出一个container
docker run -d -it --name my-centos centos

(3)进入my-centos容器中
docker exec -it my-centos bash

(4)输入vim命令
bash: vim: command not found

(5)我们要做的是 对该container进行修改,也就是安装一下vim命令,然后将其生成一个新的centos

(6)在centos的container中安装vim
yum install -y vim

(7)退出容器,将其生成一个新的centos,名称为"vim-centos-image"
docker commit my-centos vim-centos-image

(8)查看镜像列表,并且基于"vim-centos-image"创建新的容器
docker run -d -it --name my-vim-centos vim-centos-image

(9)进入到my-vim-centos容器中,检查vim命令是否存在
docker exec -it my-vim-centos bash
vim

可以通过 docker commit 命令基于一个 container 重新生成一个 image,但是一般得到 image 的 方式不建议这么做,不然 image 怎么来的就全然不知道了。

2.2.2 container 资源限制

如果不对 container 的资源做限制,它就会无限制地使用物理机的资源,这样显然是不合适的。

查看资源情况 :

1
docker stats

2.2.2.1 内存限制

1
2
3
--memory Memory limit
如果不设置 --memory-swap,其大小和memory一样
docker run -d --memory 100M --name tomcat1 tomcat

2.2.2.2 CPU 限制

1
2
--cpu-shares 权重
docker run -d --cpu-shares 10 --name tomcat2 tomcat

2.2.2.3 图形化资源监控

https://github.com/weaveworks/scope

1
2
3
4
5
6
7
sudo curl -L git.io/scope -o /usr/local/bin/scope
sudo chmod a+x /usr/local/bin/scope
scope launch 39.108.121.24

# 停止scope scope stop
# 同时监控两台机器,在两台机器中分别执行如下命令
scope launch ip1 ip2

2.2.3 container 常见操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
(1)根据镜像创建容器
docker run -d --name -p 9090:8080 my-tomcat tomcat

(2)查看运行中的container
docker ps

(3)查看所有的container[包含退出的]
docker ps -a

(4)删除container
docker rm containerid
docker rm -f $(docker ps -a) 删除所有container

(5)进入到一个container中
docker exec -it container bash

(6)根据container生成image
docker commit my-centos vim-centos-image

(7)查看某个container的日志
docker logs container

(8)查看容器资源使用情况
docker stats

(9)查看容器详情信息
docker inspect container

(10)停止/启动容器
docker stop/start container

2.3 底层技术支持

Container 是一种轻量级的虚拟化技术,不用模拟硬件创建虚拟机。 Docker 是基于 Linux Kernel 的 Namespace、CGroups、UnionFileSystem 等技术封装成的一种自 定义容器格式,从而提供一套虚拟运行环境。

Namespace:用来做隔离的,比如 pid[进程]、net[网络]、mnt[挂载点]等

CGroups: Controller Groups 用来做资源限制,比如内存和 CPU 等

Union file systems:用来做 image 和 container

03 附件

3.1 mac 搭建 docker、docker-compose 环境

https://juejin.im/post/5affada36fb9a07abf72c6e5

3.2 docker-compose.yml 配置详解

https://juejin.im/post/5aed4a776fb9a07a9918bb42

待续…