docker
Life is a journey, not the destination, but the scenery along the should be and the mood at the view.
人生就是一场旅行,不在乎目的地,在乎的应该是沿途的风景以及看风景的心情。
1 Docker安装
1.1 Docker的基本组成

镜像(image):docker镜像就好比是一个目标,可以通过这个目标来创建容器服务,tomcat镜像 —> run —> 容器(提供服务器),通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中的)。
容器(container):Docker利用容器技术,独立运行一个或者一组应用,通过镜像来创建的。启动,停止,删除,基本命令。目前就可以把这个容器理解为就是一个简易的Linux系统。
仓库(repository):仓库就是存放镜像的地方。仓库分为公有仓库和私有仓库(很类似git)。Docker Hub是国外的。 阿里云...都有容器服务器(配置镜像加速!)。
1.2 安装Docker
1.2.1 环境准备
Linux要求内核3.0以上。
➜ ~ uname -r
4.15.0-96-generic # 要求3.0以上
➜ ~ cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.4 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.4 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/" BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy- policy"VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
1.2.2 安装
帮助文档:https://docs.docker.com/engine/install/
# 1.卸载旧版本
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
# 2.需要的安装包
yum install -y yum-utils
# 3.设置镜像的仓库
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
# 默认是从国外的,不推荐
# 推荐使用国内的
yum-config-manager \
--add-repo \
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 更新yum软件包索引
yum makecache fast
# 4.安装docker相关的 docker-ce是社区版 而ee是企业版
yum install docker-ce docker-ce-cli containerd.io
# 5. 使用docker version查看是否按照成功
docker version
# 6. 测试
docker run hello-world
# 7. 测试
➜ ~ docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
# 8.查看一下下载的镜像
➜ ~ docker images REPOSITORY TAG SIZE
hello-world latest 13.3kB
了解:卸载docker
# 1. 卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
# 2. 删除资源
rm -rf /var/lib/docker
# /var/lib/docker 是docker的默认工作路径!
1.2.3 底层原理
- Docker是怎么工作的?
Docker是一个Client-Server结构的系统,Docker的守护进程运行在主机上。通过Socket从客户端访问!
Docker-Server接收到Docker-Client的指令,就会执行这个命令!

-
为什么Docker比Vm快
docker有着比虚拟机更少的抽象层。由于docker不需要Hypervisor实现硬件资源虚拟化,运行在 docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。
docker利用的是宿主机的内核,而不需要Guest OS。GuestOS:VM(虚拟机)里的系统(OS);HostOS:物理机里的系统(OS)。
因此,当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。然而避免引导、加载操作系统内核是个比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载GuestOS,这个新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了这个复杂的过程,因此新建一个docker容器只需要几秒钟。
2 Docker的常用命令
2.1 帮助命令
# 显示docker的版本信息。
docker version
# 显示docker的系统信息,包括镜像和容器的数量
docker info
# 帮助命令
docker -help
docker COMMAND --help
# 帮助文档的地址
# https://docs.docker.com/engine/reference/commandline/build/
2.2 镜像命令
#查看所有本地主机上的镜像 可以使用docker image ls代替
docker images
#搜索镜像
docker search
#下载镜像
docker pull
#删除镜像
docker rmi
2.2.1 docker images
查看所有本地的主机上的镜像
➜ ~ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d1165f221234 3 months ago 13.3kB
# 解释
# REPOSITORY 镜像的仓库源
# TAG 镜像的标签
# IMAGE ID 镜像的id
# CREATED 镜像的创建时间
# SIZE 镜像的大小
# 可选项
Options:
# 列出 所有镜像
-a, --all Show all images (default hides intermediate images)
# 只显示镜像的id
-q, --quiet Only show numeric IDs
# 显示镜像的摘要信息
--digests Show digests
# 显示完整的镜像信息
--no-trunc Don't truncate output
➜ ~ docker images -aq # 显示所有镜像的id e73346bdf465
d03312117bb0
d03312117bb0
602e111c06b6
2869fc110bf7
470671670cac
bf756fb1ae65
5acf0e8da90b
2.2.2 docker pull
下载镜像
# 下载镜像 docker pull 镜像名[:tag]
➜ ~ docker pull tomcat:8
# 如果不写tag,默认就是latest
8: Pulling from library/tomcat
# 分层下载: docker image 的核心 联合文件系统
90fe46dd8199: Already exists
35a4f1977689: Already exists
bbc37f14aded: Already exists
74e27dc593d4: Already exists
93a01fbfad7f: Already exists
1478df405869: Pull complete
64f0dd11682b: Pull complete
68ff4e050d11: Pull complete
f576086003cf: Pull complete
3b72593ce10e: Pull complete
# 签名 防伪
Digest: sha256:0c6234e7ec9d10ab32c06423ab829b32e3183ba5bf2620ee66de866df640a027
# 真实地址
Status: Downloaded newer image for tomcat:8 docker.io/library/tomcat:8
# 等价于
docker pull tomcat:8
docker pull docker.io/library/tomcat:8
2.2.3 docker rmi
删除镜像
# 删除指定的镜像
➜ ~ docker rmi -f 镜像id
# 删除指定的镜像
➜ ~ docker rmi -f 镜像id 镜像id 镜像id 镜像id
# 删除全部的镜像
➜ ~ docker rmi -f $(docker images -aq)
2.3 容器命令
说明:我们有了镜像才可以创建容器
# 新建容器并启动
docker run 镜像id
# 列出所有运行的容器
docker ps
# 删除指定容器
docker rm 容器id
# 启动容器
docker start 容器id
# 重启容器
docker restart 容器id
# 停止当前正在运行的容器
docker kill 容器id
# 强制停止当前容器
docker stop 容器id
2.3.0 docker container
➜ ~ docker container
Usage: docker container COMMAND
Manage containers
Commands:
attach Attach local standard input, output, and error streams to a running container
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes to files or directories on a container's filesystem
exec Run a command in a running container
export Export a container's filesystem as a tar archive
inspect Display detailed information on one or more containers
kill Kill one or more running containers
logs Fetch the logs of a container
ls List containers
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
prune Remove all stopped containers
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
run Run a command in a new container
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
wait Block until one or more containers stop, then print their exit codes
Run 'docker container COMMAND --help' for more information on a command.
2.3.1 docker run
# 新建容器并启动
docker run [可选参数] image | docker container run [可选参数] image
# 参数说明
--name="Name" 容器名字 tomcat01 tomcat02 用来区分容器
-d 后台方式运行
-it 使用交互方式运行,进入容器查看内容
-p 指定容器的端口 -p 8080(宿主机):8080(容器)
-p ip:主机端口:容器端口
-p 主机端口:容器端口(常用)
-p 容器端口
-P(大写) 随机指定端口
# 测试、启动并进入容器
➜ ~ docker run -it centos /bin/bash
Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
8a29a15cefae: Already exists
Digest: sha256:fe8d824220415eed5477b63addf40fb06c3b049404242b31982106ac204f6700 Status: Downloaded newer image for centos:latest
[root@95039813da8d /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@95039813da8d /]# exit # 从容器退回主机
exit
➜ ~ls
shell user.txt
2.3.2 docker ps
# 列出当前正在运行的容器
docker ps
-a, --all Show all containers (default shows just running)
-n, --last int Show n last created containers (includes all states)
(default -1)
-q, --quiet Only display numeric IDs
# --------退出容器--------
exit # 容器直接退出
ctrl +P # 容器不停止退出
2.3.3 docker rm
# 删除容器
docker rm 容器id # 删除指定的容器,不能删除正在运行的容器,如果要强制删除 rm -rf
docker rm -f $(docker ps -aq) # 删除指定的容器
docker ps -a -q|xargs docker rm # 删除所有的容器
# 启动和停止容器的操作
docker start 容器id # 启动容器
docker restart 容器id # 重启容器
docker stop 容器id # 停止当前正在运行的容器
docker kill 容器id # 强制停止当前容器
2.4 常用其他命令
# 后台启动命令
docker run -d 镜像名
# 测试
➜ ~ docker run -d centos
a8f922c255859622ac45ce3a535b7a0e8253329be4756ed6e32265d2dd2fac6c
➜ ~ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# 问题docker ps. 发现centos 停止了
# 常见的坑,docker容器使用后台运行,就必须要有要一个前台进程,docker发现没有应用,就会自动停止
# nginx,容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了
# 进入当前正在运行的容器
# 我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置
# 命令
docker exec -it 容器id bashshell
# 测试
➜ ~ docker exec -it 55321bcae33d /bin/bash
[root@55321bcae33d /]#
# 方式二
docker attach 容器id
# 测试
docker attach 55321bcae33d
正在执行当前的代码...
# 区别
# docker exec 进入当前容器后开启一个新的终端,可以在里面操作。(常用)
# docker attach 进入容器正在执行的终端
# 从容器内拷贝到主机上
docker cp 容器id:容器内路径 主机目的路径
2.5 容器错误日志
# 例:实时查看docker容器名为user-uat的最后10行日志
docker logs -f -t --tail 10 user-uat
# 例:查看指定时间后的日志,只显示最后100行:
docker logs -f -t --since="2018-02-08" --tail=100 user-uat
# 例:查看最近30分钟的日志:
docker logs --since 30m user-uat
# 例:查看某时间之后的日志:
docker logs -t --since="2018-02-08T13:23:37" user-uat
# 例:查看某时间段日志:
docker logs -t --since="2018-02-08T13:23:37" --until "2018-02-09T12:23:37" user-uat
# 例:将错误日志写入文件:
docker logs -f -t --since="2018-02-18" user-uat | grep error >> logs_error.txt
2.6 docker所有命令

3 Docker镜像
镜像是什么
镜像是一种轻量级、可执行的独立软件保,用来打包软件运行环境和基于运行环境开发的软件,他包含运行某 个软件所需的所有内容,包括代码、运行时库、环境变量和配置文件。
将所有的应用和环境,直接打包为docker镜像,就可以直接运行。
3.1 Docker镜像加载原理
3.1.1 UnionFs (联合文件系统)
我们下载的时候看到一层层的下载就是这个。
UnionFs(联合文件系统):Union文件系统(UnionFs)是一种分层、轻量级并且高性能的文件系统,他支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下( unite several directories into a single virtual filesystem)。
Union文件系统是 Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
3.1.2 Docker镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含 bootloader和 Kernel, bootloader主要是引导加 kernel, Linux刚启动时会加bootfs文件系统,在 Docker镜像的最底层是 bootfs。这一层与我们典型的 Linux/Unix系统是一样的,包含boot加載器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由 bootfs转交给内核,此时系统也会卸载bootfs。
rootfs(root file system),在 bootfs之上。包含的就是典型 Linux系统中 的/dev,/proc,/bin,/etc等标准目录和文件。 rootfs就是各种不同的操作系统发行版,比如 Ubuntu, Centos等等。
平时我们安装进虚拟机的CentOS都是好几个G,为什么Docker这里才200M?
对于个精简的OS,rootfs可以很小,只需要包合最基本的命令,工具和程序库就可以了,因为底层直接用 Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的Linux发行版, boots基本是一致的, rootfs会有差別,因此不同的发行版可以公用bootfs。
虚拟机是分钟级别,容器是秒级!
3.2 分层理解
我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层层的在下载。
为什么Docker镜像要采用这种分层的结构呢?
最大的好处,莫过于资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。
查看镜像分层的方式可以通过docker image inspect 命令:
[root@localhost admin]# docker image inspect hello-world
[
{
"Id": "sha256:feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412",
"RepoTags": [
"hello-world:latest"
],
"RepoDigests": [
"hello-world@sha256:37a0b92b08d4919615c3ee023f7ddb068d12b8387475d64c622ac30f45c29c51",
"hello-world@sha256:393b81f0ea5a98a7335d7ad44be96fe76ca8eb2eaa76950eb8c989ebf2b78ec0"
],
"Parent": "",
"Comment": "",
"Created": "2021-09-23T23:47:57.442225064Z",
"Container": "8746661ca3c2f215da94e6d3f7dfdcafaff5ec0b21c9aff6af3dc379a82fbc72",
"ContainerConfig": {
"Hostname": "8746661ca3c2",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"/hello\"]"
],
"Image": "sha256:b9935d4e8431fb1a7f0989304ec86b3329a99a25f5efdc7f09f3f8c41434ca6d",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"DockerVersion": "20.10.7",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/hello"
],
"Image": "sha256:b9935d4e8431fb1a7f0989304ec86b3329a99a25f5efdc7f09f3f8c41434ca6d",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"Architecture": "amd64",
"Os": "linux",
"Size": 13256,
"VirtualSize": 13256,
"GraphDriver": {
"Data": {
"MergedDir": "/var/lib/docker/overlay2/17759ac15742b0c51a75dfeab92146e97fd26bc22e2c8288cd5594f9c6597356/merged",
"UpperDir": "/var/lib/docker/overlay2/17759ac15742b0c51a75dfeab92146e97fd26bc22e2c8288cd5594f9c6597356/diff",
"WorkDir": "/var/lib/docker/overlay2/17759ac15742b0c51a75dfeab92146e97fd26bc22e2c8288cd5594f9c6597356/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:e07ee1baac5fae6a26f30cabfe54a36d3402f96afda318fe0a96cec4ca393359"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]
[root@localhost admin]#
理解:
所有的 Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。
举一个简单的例子,假如基于 Ubuntu Linux16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加 Python包, 就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创健第三个镜像层,该像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。

在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。
Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。
Linux上可用的存储引撃有AUFS、 Overlay2、 Device Mapper、Btrfs以及ZFS。顾名思义,每种存储 引擎都基于 Linux中对应的。
件系统或者块设备技术,井且每种存储引擎都有其独有的性能特点。
Docker在 Windows上仅支持 windowsfilter 一种存储引擎,该引擎基于NTFS文件系统之上实现了分层 和CoW [1]。
所有镜像层堆并合井,对外提供统一的视图。
Docker 镜像都是只读的,当容器启动时,一个新的可写层加载到镜像的顶部!这一层就是我们通常说的容器层,容器之下的都叫镜像层。
3.3 commit镜像
docker commit 提交容器成为一个新的副本
# 命令和git原理类似 docker commit -m="描述信息" -a="作者" 容器id 目标镜像名:[TAG]
实战测试
# 1、启动一个默认的tomcat
docker run -d -p 8080:8080 tomcat
# 2、发现这个默认的tomcat 是没有webapps应用,官方的镜像默认webapps下面是没有文件的!
docker exec -it 容器id
# 3、拷贝文件进去
# 4、将操作过的容器通过commit调教为一个镜像!我们以后就使用我们修改过的镜像即可,这就是我们自己的一个修改的镜像。
# docker commit -m="描述信息" -a="作者" 容器id 目标镜像名:[TAG]
docker commit -a="kuangshen" -m="add webapps app" 容器id tomcat02:1.0
如果你想要保存当前容器的状态,就可以通过commit来提交,获得一个镜像,就好比我们我们使用虚拟机的快照。
4 Dockerfile
4.1 什么是 Dockerfile
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
4.2 使用 Dockerfile 定制镜像
1、下面以定制一个 nginx 镜像(构建好的镜像内会有一个 /usr/share/nginx/html/index.html 文件)
在一个空目录下,新建一个名为 Dockerfile 文件,并在文件内添加以下内容:
FROM nginx
RUN echo '这是一个本地构建的nginx镜像' > /usr/share/nginx/html/index.html
2、FROM 和 RUN 指令的作用
FROM:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。
RUN:用于执行后面跟着的命令行命令。有以下俩种格式:
shell 格式:
RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。
exec 格式:
RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline
注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:
FROM centos
RUN yum install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz
# 以上执行会创建 3 层镜像。可简化为以下格式:
FROM centos
RUN yum install wget \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& tar -xvf redis.tar.gz
如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。
4.3 开始构建镜像
在 Dockerfile 文件的存放目录下,执行构建动作。
以下示例,通过目录下的 Dockerfile 构建一个 nginx:v3(镜像名称:镜像标签)。
注:最后的 . 代表本次执行的上下文路径。
$ docker build -t nginx:v3 .

以上显示,说明已经构建成功。
4.4 上下文路径
什么是上下文路径呢?
上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。
解析:由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。
如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。
注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。
4.5 指令详解
COPY
复制指令,从上下文目录中复制文件或者目录到容器里指定路径。
格式:
COPY [--chown=<user>:<group>] <源路径1>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
[--chown=
<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:
COPY hom* /mydir/
COPY hom?.txt /mydir/
<目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
ADD
ADD 指令和 COPY 的使用格类似(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:
- ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
- ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
CMD
类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
- CMD 在docker run 时运行。
- RUN 是在 docker build。
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
格式:
CMD <shell 命令>
CMD ["<可执行文件或命令>","<param1>","<param2>",...]
CMD ["<param1>","<param2>",...] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。
ENTRYPOINT
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 CMD 指令指定的程序。
优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。
注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
格式:
ENTRYPOINT ["<executeable>","<param1>","<param2>",...]
可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。
示例:
假设已通过 Dockerfile 构建了 nginx:test 镜像:
FROM nginx
ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参
1、不传参运行
$ docker run nginx:test
容器内会默认运行以下命令,启动主进程。
nginx -c /etc/nginx/nginx.conf
2、传参运行
$ docker run nginx:test -c /etc/nginx/new.conf
容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)
nginx -c /etc/nginx/new.conf
ENV
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
格式:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:
ENV NODE_VERSION 7.2.0
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"
ARG
构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。
格式:
ARG <参数名>[=<默认值>]
VOLUME
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
作用:
- 避免重要的数据,因容器重启而丢失,这是非常致命的。
- 避免容器不断变大。
格式:
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
EXPOSE
仅仅只是声明端口。
作用:
- 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
- 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
格式:
EXPOSE <端口1> [<端口2>...]
WORKDIR
指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。
docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。
格式:
WORKDIR <工作目录路径>
USER
用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
格式:
USER <用户名>[:<用户组>]
HEALTHCHECK
用于指定某个程序或者指令来监控 docker 容器服务的运行状态。
格式:
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。
ONBUILD
用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。
格式:
ONBUILD <其它指令>
LABEL
LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
比如我们可以添加镜像的作者:
LABEL org.opencontainers.image.authors="runoob"
5 Docker安装nginx
在已获取超级用户权限的条件下
1、拉取镜像
docker pull nginx
2、查看镜像
docker images
3、创建本地挂载目录
mkdir -p /home/mynginx/{conf,conf.d,html,logs}
4、随便启动一个nginx
docker run docker.io/nginx
5、复制容器内容到本地路径
docker cp 容器id:/etc/nginx/nginx.conf /home/mynginx/conf/nginx.conf
docker cp 容器id:/etc/nginx/conf.d/default.conf /home/mynginx/conf.d/default.conf
6、停止并删除之前创建的 nginx 容器
docker stop 容器id
docker rm 容器id
7、创建并挂载容器
docker run -p 80:80 --name mynginx --privileged=true -v /home/mynginx/html:/usr/share/nginx/html -v /home/mynginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro -v /home/mynginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf -v /home/mynginx/logs:/var/log/nginx -d nginx
8、在本地挂载目录 /home/mynginx/html 下编写一个简单的 html页面
移动
cd /home/mynginx/html/
创建
touch index.html
进入编写
vi index.html
6 docker安装zookeeper
- 下载:
[root@localhost admin]# docker pull zookeeper
- 查看镜像详情
[root@localhost admin]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/nginx latest 5a3221f0137b 13 days ago 126 MB
docker.io/zookeeper latest 3487af26dee9 13 days ago 225 MB
docker.io/registry latest f32a97de94e1 5 months ago 25.8 MB
docker.io/mongo latest 8bf72137439e 12 months ago 380 MB
docker.io/influxdb latest 34de2bdc2d7f 12 months ago 213 MB
docker.io/centos latest 5182e96772bf 12 months ago 200 MB
docker.io/grafana/grafana latest 3e16e05be9a3 13 months ago 245 MB
docker.io/hello-world latest 2cb0d9787c4d 13 months ago 1.85 kB
docker.io/java latest d23bdf5b1b1b 2 years ago 643 MB
[root@localhost admin]# docker inspect 3487af26dee9
[
{
"Id": "sha256:3487af26dee9ef9eacee9a97521bc4f0243bef0b285247258c32f4a03cab92c5",
"RepoTags": [
"docker.io/zookeeper:latest"
],
"RepoDigests": [
"docker.io/zookeeper@sha256:175d6bb1471e1e37a48bfa41a9da047c80fade60fd585eae3a0e08a4ce1d39ed"
],
"Parent": "",
"Comment": "",
"Created": "2019-08-15T06:10:50.178554969Z",
"Container": "9a38467115f1952161d6075135d5c5287967282b834cfe68183339c810f9652b",
"ContainerConfig": {
"Hostname": "9a38467115f1",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"2181/tcp": {},
"2888/tcp": {},
"3888/tcp": {},
"8080/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/openjdk-8/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/apache-zookeeper-3.5.5-bin/bin",
"LANG=C.UTF-8",
"JAVA_HOME=/usr/local/openjdk-8",
"JAVA_VERSION=8u222",
"JAVA_BASE_URL=https://github.com/AdoptOpenJDK/openjdk8-upstream-binaries/releases/download/jdk8u222-b10/OpenJDK8U-jre_",
"JAVA_URL_VERSION=8u222b10",
"ZOO_CONF_DIR=/conf",
"ZOO_DATA_DIR=/data",
"ZOO_DATA_LOG_DIR=/datalog",
"ZOO_LOG_DIR=/logs",
"ZOO_TICK_TIME=2000",
"ZOO_INIT_LIMIT=5",
"ZOO_SYNC_LIMIT=2",
"ZOO_AUTOPURGE_PURGEINTERVAL=0",
"ZOO_AUTOPURGE_SNAPRETAINCOUNT=3",
"ZOO_MAX_CLIENT_CNXNS=60",
"ZOO_STANDALONE_ENABLED=true",
"ZOO_ADMINSERVER_ENABLED=true",
"ZOOCFGDIR=/conf"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"zkServer.sh\" \"start-foreground\"]"
],
"ArgsEscaped": true,
"Image": "sha256:20bf3cc1bd5b5766b79da5265e94007d0802ce241df1636d0f63e211a79a0e3e",
"Volumes": {
"/data": {},
"/datalog": {},
"/logs": {}
},
"WorkingDir": "/apache-zookeeper-3.5.5-bin",
"Entrypoint": [
"/docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {}
},
"DockerVersion": "18.06.1-ce",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"2181/tcp": {},
"2888/tcp": {},
"3888/tcp": {},
"8080/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/openjdk-8/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/apache-zookeeper-3.5.5-bin/bin",
"LANG=C.UTF-8",
"JAVA_HOME=/usr/local/openjdk-8",
"JAVA_VERSION=8u222",
"JAVA_BASE_URL=https://github.com/AdoptOpenJDK/openjdk8-upstream-binaries/releases/download/jdk8u222-b10/OpenJDK8U-jre_",
"JAVA_URL_VERSION=8u222b10",
"ZOO_CONF_DIR=/conf",
"ZOO_DATA_DIR=/data",
"ZOO_DATA_LOG_DIR=/datalog",
"ZOO_LOG_DIR=/logs",
"ZOO_TICK_TIME=2000",
"ZOO_INIT_LIMIT=5",
"ZOO_SYNC_LIMIT=2",
"ZOO_AUTOPURGE_PURGEINTERVAL=0",
"ZOO_AUTOPURGE_SNAPRETAINCOUNT=3",
"ZOO_MAX_CLIENT_CNXNS=60",
"ZOO_STANDALONE_ENABLED=true",
"ZOO_ADMINSERVER_ENABLED=true",
"ZOOCFGDIR=/conf"
],
"Cmd": [
"zkServer.sh",
"start-foreground"
],
"ArgsEscaped": true,
"Image": "sha256:20bf3cc1bd5b5766b79da5265e94007d0802ce241df1636d0f63e211a79a0e3e",
"Volumes": {
"/data": {},
"/datalog": {},
"/logs": {}
},
"WorkingDir": "/apache-zookeeper-3.5.5-bin",
"Entrypoint": [
"/docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": null
},
"Architecture": "amd64",
"Os": "linux",
"Size": 225126346,
"VirtualSize": 225126346,
"GraphDriver": {
"Name": "overlay2",
"Data": {
"LowerDir": "/var/lib/docker/overlay2/92185ebf7638a7b34180cfb87795dd758405cbad4fd0139b92a227d1a4b61847/diff:/var/lib/docker/overlay2/8787e91f5c03a7c03cee072019eca49a0402a0a0902be39ed0b5d651a79cce35/diff:/var/lib/docker/overlay2/ce5864ddfa4d1478047aa9fcaa03744e8a4078ebe43b41e7836c96c54c724044/diff:/var/lib/docker/overlay2/fc99437bcfbabb9e8234c06c90d1c60e58c34ac053aff1adc368b7ad3a50c158/diff:/var/lib/docker/overlay2/1779297a8980830229bd4bf58bd741730956d6797332fd07b863a1b48dcb6fa2/diff:/var/lib/docker/overlay2/ee735aa3608d890ac4751dd93581a67cb54a5dd4714081e9d09d0ebd9dbc3501/diff:/var/lib/docker/overlay2/cf6b3cbc42f3c8d1fb09b29db0dafbb4dceb120925970ab8a3871eaa8562414c/diff",
"MergedDir": "/var/lib/docker/overlay2/a7fcc1b78c472cde943f20d1d4495f145308507b5fe3da8800c33dc4ce426156/merged",
"UpperDir": "/var/lib/docker/overlay2/a7fcc1b78c472cde943f20d1d4495f145308507b5fe3da8800c33dc4ce426156/diff",
"WorkDir": "/var/lib/docker/overlay2/a7fcc1b78c472cde943f20d1d4495f145308507b5fe3da8800c33dc4ce426156/work"
}
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:1c95c77433e8d7bf0f519c9d8c9ca967e2603f0defbf379130d9a841cca2e28e",
"sha256:2bf534399acac9c6b09a0b1d931223808000b04400a749f08187ed9ee435738d",
"sha256:eb25e0278d41b9ac637d8cb2e391457cf44ce8d2bfe0646d0c9faefc96413f91",
"sha256:e54bd3566d9ef3e1309a5af6caf8682f32c6ac4d6adfcbd3e601cfee4e2e0e85",
"sha256:c79435051d529a7b86f5f9fc32e7e2ec401929434e5596f02a2af731f55c9f28",
"sha256:76e0d7b2d700e6d17924b985703c7b5b84fb39ddcc0a1181b41217c2a11dffc4",
"sha256:eecdc37df6afd77091641588f9639f63b65e8eb141e56529e00da44419c5bd04",
"sha256:36e788f2d91a89375df5901f31cca33776f887c00ddfd3cf9f2466fa4cb794d6"
]
}
}
]
6.1 单机
[root@localhost admin]# docker run -d -p 2181:2181 --name zookeeper-test --restart always zookeeper
d5c6f857cd88c342acf63dd58e838a4cdf912daa6c8c0115091147136e819307
[root@localhost admin]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2f1acbba2d41 zookeeper "/docker-entrypoint.…" 37 hours ago Up 11 minutes 2888/tcp, 3888/tcp, 0.0.0.0:2181->2181/tcp, :::2181->2181/tcp, 8080/tcp zookeeper-test
[root@localhost admin]# docker exec -it zookeeper-test /bin/bash
root@2f1acbba2d41:/apache-zookeeper-3.7.0-bin# ./bin/zk
root@2f1acbba2d41:/apache-zookeeper-3.7.0-bin# ./bin/zkCli.sh
Connecting to localhost:2181
...
[zk: localhost:2181(CONNECTED) 0] ls /
[country, data-archive-job, zookeeper]
[zk: localhost:2181(CONNECTED) 1]
6.2 集群
环境:单台宿主机(192.168.192.128),启动三个zookeeper容器。
这里涉及一个问题,就是Docker容器之间通信的问题,这个很重要!
Last login: Sun Nov 7 23:39:12 on ttys001
[root@localhost admin]# docker network ls
NETWORK ID NAME DRIVER SCOPE
a3dc42edd1f5 bridge bridge local
4ab0b24b5b0b host host local
6c6bcc530bdc none null local
[root@localhost admin]#
Docker有三种网络模式,bridge、host、none,在你创建容器的时候,不指定--network默认是bridge。
bridge:为每一个容器分配IP,并将容器连接到一个docker0虚拟网桥,通过docker0网桥与宿主机通信。也就是说,此模式下,你不能用宿主机的IP+容器映射端口来进行Docker容器之间的通信。
host:容器不会虚拟自己的网卡,配置自己的IP,而是使用宿主机的IP和端口。这样一来,Docker容器之间的通信就可以用宿主机的IP+容器映射端口
none:无网络。
==================================================
先在本地创建目录:
[root@localhost admin]# mkdir /usr/local/zookeeper-cluster
[root@localhost admin]# mkdir /usr/local/zookeeper-cluster/node1
[root@localhost admin]# mkdir /usr/local/zookeeper-cluster/node2
[root@localhost admin]# mkdir /usr/local/zookeeper-cluster/node3
[root@localhost admin]# ll /usr/local/zookeeper-cluster/
total 0
drwxr-xr-x. 2 root root 6 Aug 28 23:02 node1
drwxr-xr-x. 2 root root 6 Aug 28 23:02 node2
drwxr-xr-x. 2 root root 6 Aug 28 23:02 node3
【正确方式开始】
[root@localhost admin]# docker network create --driver bridge --subnet=172.18.0.0/16 --gateway=172.18.0.1 zookeeper-net
8257c501652a214d27efdf5ef71ff38bfe222c3a2a7898be24b8df9db1fb3b13
[root@localhost admin]# docker network ls
NETWORK ID NAME DRIVER SCOPE
5fc1ce4362af bridge bridge local
6aa33e21444e host host local
20e563b93ce9 none null local
8257c501652a zookeeper-net bridge local
[root@localhost admin]# docker network inspect 8257c501652a
[
{
"Name": "zookeeper-net",
"Id": "8257c501652a214d27efdf5ef71ff38bfe222c3a2a7898be24b8df9db1fb3b13",
"Created": "2019-08-29T06:08:01.442601483-04:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
然后我们修改一下zookeeper容器的创建命令。
docker run -d -p 2181:2181 --name zookeeper-node1 --privileged --network zookeeper-net --ip 172.18.0.2 \
-v /Users/xiaojinzi/docker/zookeeper/zookeeper-cluster/node1/data:/data \
-v /Users/xiaojinzi/docker/zookeeper/zookeeper-cluster/node1/datalog:/datalog \
-v /Users/xiaojinzi/docker/zookeeper/zookeeper-cluster/node1/logs:/logs \
-e ZOO_MY_ID=1 \
-e "ZOO_SERVERS=server.1=172.18.0.2:2888:3888;2181 server.2=172.18.0.3:2888:3888;2181 server.3=172.18.0.4:2888:3888;2181" zookeeper
docker run -d -p 2182:2181 --name zookeeper-node2 --privileged --network zookeeper-net --ip 172.18.0.3 \
-v /Users/xiaojinzi/docker/zookeeper/zookeeper-cluster/node2/data:/data \
-v /Users/xiaojinzi/docker/zookeeper/zookeeper-cluster/node2/datalog:/datalog \
-v /Users/xiaojinzi/docker/zookeeper/zookeeper-cluster/node2/logs:/logs \
-e ZOO_MY_ID=2 \
-e "ZOO_SERVERS=server.1=172.18.0.2:2888:3888;2181 server.2=172.18.0.3:2888:3888;2181 server.3=172.18.0.4:2888:3888;2181" zookeeper
docker run -d -p 2183:2181 --name zookeeper-node3 --privileged --network zookeeper-net --ip 172.18.0.4 \
-v /Users/xiaojinzi/docker/zookeeper/zookeeper-cluster/node3/data:/data \
-v /Users/xiaojinzi/docker/zookeeper/zookeeper-cluster/node3/datalog:/datalog \
-v /Users/xiaojinzi/docker/zookeeper/zookeeper-cluster/node3/logs:/logs \
-e ZOO_MY_ID=3 \
-e "ZOO_SERVERS=server.1=172.18.0.2:2888:3888;2181 server.2=172.18.0.3:2888:3888;2181 server.3=172.18.0.4:2888:3888;2181" zookeeper
-
由于2888 、3888 不需要暴露,就不映射了;
-
指定自己的网络,并指定IP;
-
每个容器之间环境是隔离的,所以容器内所用的端口一样:2181/2888/3888

运行结果:
[root@localhost admin]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a447e22e21e1 zookeeper "/docker-entrypoint.…" 3 minutes ago Up 3 minutes 2888/tcp, 3888/tcp, 8080/tcp, 0.0.0.0:2183->2181/tcp, :::2183->2181/tcp zookeeper-node3
9d371fa542c2 zookeeper "/docker-entrypoint.…" 3 minutes ago Up 3 minutes 2888/tcp, 3888/tcp, 8080/tcp, 0.0.0.0:2182->2181/tcp, :::2182->2181/tcp zookeeper-node2
406ab058f944 zookeeper "/docker-entrypoint.…" 3 minutes ago Up 3 minutes 2888/tcp, 3888/tcp, 0.0.0.0:2181->2181/tcp, :::2181->2181/tcp, 8080/tcp zookeeper-node1
[root@localhost admin]#
进入容器内部验证一下:
Last login: Mon Nov 8 22:37:38 on ttys000
[root@localhost admin]# docker exec -it zookeeper-node1 bash
root@406ab058f944:/apache-zookeeper-3.7.0-bin# ./bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: follower
root@406ab058f944:/apache-zookeeper-3.7.0-bin#
在验证一下创建节点

开启防火墙,以供外部访问
firewall-cmd --zone=public --add-port=2181/tcp --permanent
firewall-cmd --zone=public --add-port=2182/tcp --permanent
firewall-cmd --zone=public --add-port=2183/tcp --permanent
systemctl restart firewalld
firewall-cmd --list-all
在本地,我用zookeeper的客户端连接虚拟机上的集群:

可以看到连接成功!

6.3 集群安装方式二
通过docker stack deploy或docker-compose安装
这里用docker-compose。先安装docker-compose
[root@localhost admin]# curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 617 0 617 0 0 145 0 --:--:-- 0:00:04 --:--:-- 145
100 15.4M 100 15.4M 0 0 131k 0 0:02:00 0:02:00 --:--:-- 136k
[root@localhost admin]# chmod +x /usr/local/bin/docker-compose
检查版本(验证是否安装成功)
[root@localhost admin]# docker-compose --version
docker-compose version 1.24.1, build 4667896b
卸载的话
rm /usr/local/bin/docker-compose
开始配置,新建三个挂载目录
[root@localhost admin]# mkdir /usr/local/zookeeper-cluster/node4
[root@localhost admin]# mkdir /usr/local/zookeeper-cluster/node5
[root@localhost admin]# mkdir /usr/local/zookeeper-cluster/node6
新建任意目录,然后在里面新建一个文件
[root@localhost admin]# mkdir DockerComposeFolder
[root@localhost admin]# cd DockerComposeFolder/
[root@localhost DockerComposeFolder]# vim docker-compose.yml
文件内容如下:(自定义网络见上面)
version: '3.1'
services:
zoo1:
image: zookeeper
restart: always
privileged: true
hostname: zoo1
ports:
- 2181:2181
volumes: # 挂载数据
- /usr/local/zookeeper-cluster/node4/data:/data
- /usr/local/zookeeper-cluster/node4/datalog:/datalog
environment:
ZOO_MY_ID: 4
ZOO_SERVERS: server.4=0.0.0.0:2888:3888;2181 server.5=zoo2:2888:3888;2181 server.6=zoo3:2888:3888;2181
networks:
default:
ipv4_address: 172.18.0.14
zoo2:
image: zookeeper
restart: always
privileged: true
hostname: zoo2
ports:
- 2182:2181
volumes: # 挂载数据
- /usr/local/zookeeper-cluster/node5/data:/data
- /usr/local/zookeeper-cluster/node5/datalog:/datalog
environment:
ZOO_MY_ID: 5
ZOO_SERVERS: server.4=zoo1:2888:3888;2181 server.5=0.0.0.0:2888:3888;2181 server.6=zoo3:2888:3888;2181
networks:
default:
ipv4_address: 172.18.0.15
zoo3:
image: zookeeper
restart: always
privileged: true
hostname: zoo3
ports:
- 2183:2181
volumes: # 挂载数据
- /usr/local/zookeeper-cluster/node6/data:/data
- /usr/local/zookeeper-cluster/node6/datalog:/datalog
environment:
ZOO_MY_ID: 6
ZOO_SERVERS: server.4=zoo1:2888:3888;2181 server.5=zoo2:2888:3888;2181 server.6=0.0.0.0:2888:3888;2181
networks:
default:
ipv4_address: 172.18.0.16
networks: # 自定义网络
default:
external:
name: zookeeper-net
注意yaml文件里不能有tab,只能有空格。
关于version与Docker版本的关系如下:

然后执行(-d后台启动)
docker-compose -f docker-compose.yml up -d

查看已启动的容器
[root@localhost DockerComposeFolder]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a2c14814037d zookeeper "/docker-entrypoin..." 6 minutes ago Up About a minute 2888/tcp, 3888/tcp, 8080/tcp, 0.0.0.0:2183->2181/tcp dockercomposefolder_zoo3_1
50310229b216 zookeeper "/docker-entrypoin..." 6 minutes ago Up About a minute 2888/tcp, 3888/tcp, 0.0.0.0:2181->2181/tcp, 8080/tcp dockercomposefolder_zoo1_1
475d8a9e2d08 zookeeper "/docker-entrypoin..." 6 minutes ago Up About a minute 2888/tcp, 3888/tcp, 8080/tcp, 0.0.0.0:2182->2181/tcp dockercomposefolder_zoo2_1
进入一个容器
[root@localhost DockerComposeFolder]# docker exec -it a2c14814037d bash
root@zoo3:/apache-zookeeper-3.5.5-bin# ./bin/zkCli.sh
Connecting to localhost:2181
....
WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0]
[zk: localhost:2181(CONNECTED) 1] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 2] create /hi
Created /hi
[zk: localhost:2181(CONNECTED) 3] ls /
[hi, zookeeper]
进入另一个容器
[root@localhost DockerComposeFolder]# docker exec -it 50310229b216 bash
root@zoo1:/apache-zookeeper-3.5.5-bin# ./bin/zkCli.sh
Connecting to localhost:2181
...
WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0] ls /
[hi, zookeeper]
本地客户端连接集群:
zkCli.cmd -server 192.168.192.128:2181,192.168.192.128:2182,192.168.192.128:2183

查看

停止所有活动容器

删除所有已停止的容器

更多docker-compose的命令:
[root@localhost DockerComposeFolder]# docker-compose --help
Define and run multi-container applications with Docker.
Usage:
docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]
docker-compose -h|--help
Options:
-f, --file FILE Specify an alternate compose file
(default: docker-compose.yml)
-p, --project-name NAME Specify an alternate project name
(default: directory name)
--verbose Show more output
--log-level LEVEL Set log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
--no-ansi Do not print ANSI control characters
-v, --version Print version and exit
-H, --host HOST Daemon socket to connect to
--tls Use TLS; implied by --tlsverify
--tlscacert CA_PATH Trust certs signed only by this CA
--tlscert CLIENT_CERT_PATH Path to TLS certificate file
--tlskey TLS_KEY_PATH Path to TLS key file
--tlsverify Use TLS and verify the remote
--skip-hostname-check Don't check the daemon's hostname against the
name specified in the client certificate
--project-directory PATH Specify an alternate working directory
(default: the path of the Compose file)
--compatibility If set, Compose will attempt to convert keys
in v3 files to their non-Swarm equivalent
Commands:
build Build or rebuild services
bundle Generate a Docker bundle from the Compose file
config Validate and view the Compose file
create Create services
down Stop and remove containers, networks, images, and volumes
events Receive real time events from containers
exec Execute a command in a running container
help Get help on a command
images List images
kill Kill containers
logs View output from containers
pause Pause services
port Print the public port for a port binding
ps List containers
pull Pull service images
push Push service images
restart Restart services
rm Remove stopped containers
run Run a one-off command
scale Set number of containers for a service
start Start services
stop Stop services
top Display the running processes
unpause Unpause services
up Create and start containers
version Show the Docker-Compose version information
7 docker安装dubbo-admin
7.1 下载镜像
若省略此步,直接执行第二步,docker会拉取最新版的dubbo-admin,拉取的好处是可以指定拉取的版本
docker pull apache/dubbo-admin
7.2 创建docker容器
将下面命令的ip地址换成个人的ip地址即可,其中8888是自己定义的dubbo-admin的访问端口,可自己定义,zookeeper的默认端口为2181,也可自己定义和修改
docker run -d \
--name dubbo-admin-test \
-v /workspace/software/dubbo/data:/data \
-p 8888:8080 \
--link zookeeper-test \
-e admin.registry.address=zookeeper://ip地址:2181 \
-e admin.config-center=zookeeper://ip地址:2181 \
-e admin.metadata-report.address=zookeeper://ip地址:2181 \
--restart=always \
docker.io/apache/dubbo-admin;
7.3 访问dubbo-admin
8 Docker安装MySQL集群【读写分离】
8.1 下载mysql镜像
docker search mysql
docker pull mysql:5.7
8.2 创建Master实例并启动
docker run -p 3307:3306 --name mysql-master \
-v /mydata/mysql/master/log:/var/log/mysql \
-v /mydata/mysql/master/data:/var/lib/mysql \
-v /mydata/mysql/master/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
修改master基本配置
vim /mydata/mysql/master/conf/my.cnf
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
注意:skip-name-resolve一定要加,不然连接mysql会超级慢
8.3 创建Slave实例并启动
docker run -p 3316:3306 --name mysql-slaver-01 \
-v /mydata/mysql/slaver/log:/var/log/mysql \
-v /mydata/mysql/slaver/data:/var/lib/mysql \
-v /mydata/mysql/slaver/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
修改slave基本配置
vim /mydata/mysql/slaver/conf/my.cnf
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
8.4 添加master主从复制部分配置
vim /mydata/mysql/master/conf/my.cnf
server-id=1
log_bin=mysql-bin
read-only=0
# 同步的数据库
binlog-do-db=gmall_ums
binlog-do-db=gmall_pms
binlog-do-db=gmall_oms
binlog-do-db=gmall_sms
binlog-do-db=gmall_cms
# 忽略同步的数据库
replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=information_schema
replicate-ignore-db=performance_schema
重启容器
8.5 添加Slave主从复制部分配置
server-id=2
log_bin=mysql-bin
read-only=1
# 同步的数据库
binlog-do-db=gmall_ums
binlog-do-db=gmall_pms
binlog-do-db=gmall_oms
binlog-do-db=gmall_sms
binlog-do-db=gmall_cms
# 忽略同步的数据库
replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=information_schema
replicate-ignore-db=performance_schema
重启容器
8.6 为master授权用户来他的同步数据
1、进入主库
docker exec -it mysql-master /bin/bash
2、进入主库mysql数据库
mysql -u root -p
- 1)、授权root可以远程访问( 主从无关,为了方便我们远程连接mysql)
grant all privileges on *.* to 'root'@'%' identified by 'root' with grant option;
flush privileges;
-
**2)、添加用来同步的用户**
GRANT REPLICATION SLAVE ON *.* to 'backup'@'%' identified by '123456';
- 3)、查看数据库的状态
show master status\G;
3、进入从库mysql数据库
- 1)、授权root可以远程访问( 主从无关,为了方便我们远程连接mysql)
grant all privileges on *.* to 'root'@'%' identified by 'root' with grant option;
flush privileges;
- 2)、设置主库连接
change master to master_host='192.168.116.129',master_user='backup',master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=0,master_port=3307;
- 3)、启动从库同步
start slave;
- 4)、查看从库状态
show slave status\G;
至此主从配置完成。

Life is a journey, not the destination, but the scenery along the should be and the mood at the view.
人生就是一场旅行,不在乎目的地,在乎的应该是沿途的风景以及看风景的心情。
浙公网安备 33010602011771号