Docker基础知识
Docker基础知识一.Docker概述1. Docker为什么出现?传统开发中的问题:一款产品:开发-上线 两套环境!应用环境,应用配置!开发-运维问题:我在我的电脑上可以运行!版本更新,导致服务不可用!对于运维来说,考验就十分大?环境配置是十分的麻烦,每一个机器都要部署环境(集群Redis、ES、Hadoop.………)!费时费力。发布一个项目(jar +(Redis MySQL jdk ES)
README
本文学习路线主要参照:
https://www.bilibili.com/video/BV1og4y1q7M4
https://www.bilibili.com/video/BV1kv411q7Qc
文章目录
一.Docker概述
1. Docker为什么出现?
传统开发中的问题:
-
一款产品:开发-上线 两套环境!应用环境,应用配置!
-
开发-运维问题:
- 我在我的电脑上可以运行!
- 版本更新,导致服务不可用!对于运维来说,考验就十分大?
- 环境配置是十分的麻烦,每一个机器都要部署环境(集群Redis、ES、Hadoop.………)!费时费力。
- 发布一个项目(jar +(Redis MySQL jdk ES)),项目能不能都带上环境安装打包!
- 之前在服务器配置一个应用的环境 Redis MySQL jdk ES Hadoop,配置超麻烦了,不能够跨平台。Windows,最后发布到 Linux!
Docker给以上的问题,提出了解决方案!
Docker的思想就来自于集装箱!
隔离:Docker核心思想!打包装箱!每个箱子是互相隔离的。Docker 通过隔离机制,可以将服务器利用到极致!
2. Docker的历史
- 2010年,几个搞IT的年轻人,就在美国成立了一家公司 dotcloud,做一些 pass的云计算服务! LXC有关的容器技术!
他们将自己的技术(容器化技术)命名 就是Docker!Docker刚刚诞生的时候,没有引起行业的注意!dotCloud,就活不下去! - 2013年,Docker开源!越来越多的人发现了docker的优点!火了,Docker每个月都会更新一个版本!
- 2014年4月9日,Docker1.0发布!
Docker为什么这么火?
因为它十分的轻巧!
在容器技术出来之前,我们都是使用虚拟机技术!虚拟机:在window中装一个Vmware,通过这个软件我们可以虚拟出来一台或者多台电脑!笨重!
虚拟机使用的是虚拟化技术,Docker的容器技术,也是一种虚拟化技术!
3. Docker简介
Docker官网: https://www.docker.com/
Docker Hub官网: https://hub.docker.com/
Docker文档: https://docs.docker.com/
3.1 Docker的定义
Docker是一个基于Go语言开发的开源的应用容器引擎;是一个轻量级容器技术;
Docker支持将软件编译成一个镜像;然后在镜像中各种软件做好配置,将镜像发布出去,其他使用者可以直接使用这个镜像;运行中的这个镜像称为容器,容器启动是非常快速的。
3.2 Docker VS 虚拟机
- 传统虚拟机,虚拟出一条硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件;
- 容器内的应用直接运行在 宿主机的内核,容器是没有自己的内核的,也没有虚拟我们的硬件,所以就轻便了;
- 每个容器间是互相隔离,每个容器内都有一个属于自己的文件系统,互不影响。
3.3 Docker的DevOps 优势
DevOps (开发、运维)
-
应用更快速的交付和部署
- 传统:一堆帮助文档,安装程序
- Docker:打包镜像发布测试,一键运行
-
更便捷的升级和扩缩容
- 使用了Docker之后,我们部署应用就和搭积木一样!
- 项目打包为一个镜像,扩展 服务器A!服务器B
-
更简单的系统运维
- 在容器化之后,我们的开发,测试环境都是高度一致的。
-
更高效的计算资源利用
- Docker是内核级别的虚拟化,可以再一个物理机上可以运行很多的容器实例!服务器的性能可以被压榨到机制!
4. Docker基本架构
镜像 image
- Docker 镜像(Image)就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。 就好似Java 中的类和对象,类就是镜像,容器就是对象!
容器 container
- Docker 利用容器(Container)独立运行的一个或一组应用。容器是用镜像创建的运行实例。
- 它可以被启动、开始、停止、删除。每个容器都是相互隔离的,保证安全的平台。
- 可以把容器看做是一个简易版的Linux环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
仓库 repository
- 仓库(Repository)是集中存放镜像文件的场所。
- 仓库(Repository)和仓库注册服务器(Registry)是有区别的。仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。
- 仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
- 最大的公开仓库是Docker Hub,存放了数量庞大的镜像供用户下载。国内的公开仓库包括阿里云、网易云等。
架构图
- Docker主机(Host):安装了Docker程序的机器(Docker直接安装在操作系统之上);
- Docker客户端(Client):连接Docker主机进行操作;
- Docker仓库(Registry):用来存放各种镜像,分为公有仓库和私有仓库,公有仓库默认是国外的Docker Hub;
- Docker镜像(Images):由各种环境和软件好的模板,放在Docker仓库中,通过镜像可创建容器服务;
- Docker容器(Container):镜像启动后的实例称为一个容器,容器是独立运行的一个或一组应用
5. Docker基本工作原理
- Docker 是一个 Client-Server结构的系统,Docker的守护进程运行在主机上。通过Socket从客户端访问!
- DockerServer 接收到Docker-Client的指令,就会执行这个命令!
二.Centos7安装Docker
1. 安装步骤
官方文档非常详细,地址: https://docs.docker.com/engine/install/centos/
#1、检查内核版本,必须是3.10及以上
cat /etc/os-release
uname -r
#2、卸载旧版本
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
#3、安装依赖包
yum install -y yum-utils
#4、设置docker镜像仓库(官网给的默认仓库在国外,如下:不建议使用)
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
#建议使用下面的阿里云docker镜像仓库
yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#5、更新一下yum软件包索引
yum makecache fast
#6、安装docker(默认最新版本) ce指社区版 ee指企业版
yum -y install docker-ce docker-ce-cli containerd.io #如果安装指定版本的docker可去官网查看https://docs.docker.com/engine/install/centos/
#7、启动docker
systemctl start docker
#8、查看docker是否安装成功
docker version
#9、运行docker测试案例
docker run hello-world # 使用 docker images 查看自动拉取到的hello-world镜像
docker run
的运行原理如下图
2. 卸载docker
# 下载依赖
yum -y remove docker-ce docker-ce-cli containerd.io
# 删除资源
rm -rf /var/lib/docker #docker的默认工作路径
3. 配置阿里云镜像加速
选配
mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://2j8ru6sk.mirror.aliyuncs.com"]
}
EOF
systemctl daemon-reload
systemctl restart docker
三.Docker常用命令
https://docs.docker.com/engine/reference/commandline
1. 帮助命令
# 显示docker的版本信息
docker version
# 显示docker的系统信息,包括镜像和容器的数量
docker info
# 帮助命令
docker --help
2. 镜像命令
2.1 查看镜像
# 查看地主机上的镜像
[root@node02 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest bf756fb1ae65 7 months ago 13.3kB
# 命令行可选项
-a, --all # 列出所有镜像
-q, --quiet # 只显示镜像的id
REPOSITORY 镜像的仓库源
TAG 镜像的标签
IMAGE ID 镜像的id
CREATED 镜像的创建时间
SIZE 镜像的大小
2.2 搜索镜像
docker search mysql
# 命令行可选项,举例
docker search mysql --dilter=STARS=3000 #搜索STARS大于3000的镜像
2.3 下载镜像
[root@node02 ~]# docker pull mysql
Using default tag: latest # 如果不写tag,默认是latest
latest: Pulling from library/mysql
bf5952930446: Pull complete # 分层下载,docker image的核心——联合文件系统
8254623a9871: Pull complete
938e3e06dac4: Pull complete
ea28ebf28884: Pull complete
f3cef38785c2: Pull complete
894f9792565a: Pull complete
1d8a57523420: Pull complete
6c676912929f: Pull complete
ff39fdb566b4: Pull complete
fff872988aba: Pull complete
4d34e365ae68: Pull complete
7886ee20621e: Pull complete
Digest: sha256:c358e72e100ab493a0304bda35e6f239db2ec8c9bb836d8a427ac34307d074ed # 签名(防伪)
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest # 镜像的真实地址 docker pull mysql 等价于 docker pull docker.io/library/mysql:latest
#指定tag(版本)下载
[root@node02 ~]# docker pull mysql:5.7
5.7: Pulling from library/mysql
bf5952930446: Already exists # 联合文件系统分层下载,在执行上面的 docker pull mysql 时已经下载过了
8254623a9871: Already exists
938e3e06dac4: Already exists
ea28ebf28884: Already exists
f3cef38785c2: Already exists
894f9792565a: Already exists
1d8a57523420: Already exists
5f09bf1d31c1: Pull complete
1b6ff254abe7: Pull complete
74310a0bf42d: Pull complete
d398726627fd: Pull complete
Digest: sha256:da58f943b94721d46e87d5de208dc07302a8b13e638cd1d24285d222376d6d84
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
2.4 删除镜像
# 删除指定的镜像
docker rmi -f 镜像id #根据IMAGE ID删除
# 删除多个镜像
docker rmi -f 镜像id 镜像id 。。。
# 删除全部镜像
docker rmi -f $(docker images -aq)
# 根据镜像的REPOSITORY删除镜像
docker images | grep "镜像名称" | awk '{print $1":"$2}' | xargs docker rmi
3. 容器命令
有了镜像才能创建容器,比如我们下载一个centos的docker镜像来测试学习
docker pull centos
3.1 启动容器
docker run [可选参数] 镜像名称
# 参数说明
--name="name" 容器名称,用来区分容器
-d 后台方式运行
-it 使用交互式运行,用来进入容器查看内容
-p 指定容器端口,有四种用法
-p IP:主机端口:容器端口 #不常用
-p 主机端口:容器端口 #最常用
-p 容器端口 #直接写容器端口,不与主机端口关联
容器端口 #可省掉-p,只写容器端口
# 启动容器并运行/bin/bash命令进入容器
[root@node02 ~]# docker run -it centos /bin/bash
WARNING: IPv4 forwarding is disabled. Networking will not work.
# 查看容器内的centos 【这是centos基础版本,很多命令都是不完善的!】
[root@9069a46e5b5b /]# ls
bin etc lib lost+found mnt proc run srv tmp var
dev home lib64 media opt root sbin sys usr
# 从容器中退会主机
[root@9069a46e5b5b ~]# exit
exit
3.2 查看容器
docker ps # 列出正在运行的容器
-a # 可选参数,列出正在运行的容器 + 历史运行的容器
-n=? # 可选参数,仅列出前?行查询结果
-q # 可选参数,只显示容器的编号
举例:
docker ps
docker ps -a
docker ps -aq
docker ps -a -n=1
3.3 退出容器
# 还是以上述centos的容器为例
exit # 退出并停止容器
Ctrl + P + Q # 仅退出容器,容器并不会停止
3.4 删除容器
# 删除指定的容器,不能删除正在运行的容器
docker rm 容器id
# 删除所有容器【-f表示强制删除】 docker ps -a -q|xargs docker rm -f
docker rm -f $(docker ps -aq)
3.5 启停容器
docker start 容器id # 启动容器
docker stop 容器id # 关闭容器
docker restart 容器id # 重启容器
docker kill 容器id # 强制停止容器
4. 其他常用命令
4.1 后台启动容器
docker run -d 镜像名
[root@node02 ~]# docker run -d centos
注意:上述命令虽然成功执行了,但是要
docker ps
命令是查询不到此容器的,说名启动的这个容器又停止了因此:docker容器使用后台运行时,必须要有一个前台应用使用,如果docker发现没有应用在使用这个容器,就会自动停止。
例如:Ngnix容器启动后,如果检测到容器没有提供服务,就会立刻停止此容器运行
4.2 查看容器日志
docker logs -f -t --tail 容器名
# 自己写一段shell脚本用centos容器运行
[root@node02 ~]# docker run -d centos /bin/sh -c "while true;do echo helloDocker;sleep 1;done"
WARNING: IPv4 forwarding is disabled. Networking will not work.
223677dd3986b57174e344c2b7f4d715e52db4e514fb4a8b2fb78ad1318c5882
[root@node02 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
223677dd3986 centos "/bin/sh -c 'while t…" 7 seconds ago Up 6 seconds angry_borg
[root@node02 ~]# docker logs -tf --tail 10 223677dd3986
2020-08-23T09:41:24.673130377Z helloDocker
2020-08-23T09:41:25.678436561Z helloDocker
... ...
-tf 含义是:显示日志
–tail 行数 含义是:要显示的日志行数
4.3 查看容器中的进程信息
docker top 容器id
# 例如
[root@node02 ~]# docker top 223677dd3986
UID PID PPID C STIME TTY TIME CMD
root 5907 5890 0 17:41 ? 00:00:00 /bin/sh -c while true;do echo helloDocker;sleep 1;done
root 6221 5907 0 17:45 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1
4.4 查看容器的元数据
docker inspect 容器id
# 例如 查询到的是json格式的十分详细的容器信息
[root@node02 ~]# docker inspect 223677dd3986
4.5 进入正在运行的容器
# 命令1
docker exec -it 容器id bashshell
# 通常,容器都是使用后台方式运行,如果想要进容器修改一些配置,常用上面的命令行进入容器,举例如下:
[root@node02 ~]# docker run -d centos /bin/sh -c "while true;do echo helloDocker;sleep 1;done"
WARNING: IPv4 forwarding is disabled. Networking will not work.
4556168d774b1c86a86348a7c9264a1602d8bc7eb5ec4a669a2c2faebe0f4cb5
[root@node02 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4556168d774b centos "/bin/sh -c 'while t…" 12 seconds ago Up 11 seconds beautiful_haibt
[root@node02 ~]# docker exec -it 4556168d774b /bin/bash
[root@4556168d774b /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 01:15 ? 00:00:00 /bin/sh -c while true;do echo helloDocker;sleep 1;done
root 42 0 0 01:15 pts/0 00:00:00 /bin/bash
root 249 1 0 01:18 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1
root 250 42 0 01:18 pts/0 00:00:00 ps -ef
# 命令2
docker attach 容器id
# 测试
[root@node02 ~]# docker attach 4556168d774b
helloDocker
helloDocker
helloDocker
... ...
命令区别:
docker exec
进入容器后后开启一个新的终端docker attach
进入容器正在执行的终端
4.6 复制容器内文件到主机
# 命令 (复制文件或目录都可以)
docker cp 容器id:容器内文件路径 目的主机的路径
# 此命令是一个手动的过程,后面我们可以使用 卷 技术,实现自动同步。如将容器的/home与本机的/home做同步
# 测试
[root@node02 ~]# docker run -it centos /bin/bash
WARNING: IPv4 forwarding is disabled. Networking will not work.
[root@aed54c3c8382 /]# touch /home/hello.java
[root@aed54c3c8382 /]# ls /home
hello.java
# Ctrl + P + Q 仅退出容器,容器并不会停止
[root@node02 ~]# ls /home
[root@node02 ~]# docker cp aed54c3c8382:/home/hello.java /home
[root@node02 ~]# ls /home
hello.java
5. 小结
命令行关键字 | 英文注释 | 译:中文 |
---|---|---|
attach | Attach to a running container | 当前 she11 下 attach 连接指定运行镜像 |
buitd | Build an image from a Dockerfile | 通过 Dockerfile 定制镜像 |
commit | Create a new image from a container changes | 提交当前容器为新的镜像 |
cp | Copy files/folders from the containers filesystem to the host path | 从容器中拷贝指定文件或者目录到宿主机中 |
create | Create a new container | 创建一个新的容器,同run,但不启动容器 |
diff | Inspect changes on a container’s filesystem | 查看 docker 容器变化 |
events | Get real time events from the server | 从 docker 服务获取容器实时事件 |
exec | Run a command in an existing container | 在已存在的容器上运行命令 |
export | Stream the contents of a container as a tar archive | 导出容器的内容流作为一个 tar 归档文件 |
import | Create a new filesystem image from the contents of a tarball | 从tar包中的内容创建一个新的文件系统映像 |
history | Show the history of an image | 展示一个镜像形成历史 |
images | List images | 列出系统当前镜像 |
info | Display system-wide information | 显示系统相关信息 |
inspect | Return low-level information on a container | 查看容器详细信息 |
kill | Kill a running container | kill 指定 docker 容器 |
load | Load an image from a tar archive | 从一个 tar 包中加载一个镜像[对应 save] |
login | Register or Login to the docker registry server | 注册或者登陆一个 docker 源服务器 |
logout | Log out from-a Docker registry server | 从当前 Docker registry 退出 |
logs | Fetch the logs of a container | 输出当前容器日志信息 |
port | Lookup the public-facing port which is NAT-ed to PRIVATE_PORT | 查看映射端口对应的容器内部源端口 |
pause | Pause all processes within a container | 暂停容器 |
ps | List containers | 列出容器列表 |
pull | Pull an image or a repository from the docker registry server | 从docker镜像源服务器拉取指定镜像或者库镜像 |
push | Push an image or a repository to the docker registry server | 推送指定镜像或者库镜像至docker源服务器 |
restart | Restart a running container | 重启运行的容器 |
rm | Remove one or more containers | 移陈一个或者多个容器 |
rmi | Remove one or more images A | 移除一个或多个镜像 |
run | Run a command in a new container | 创建一个新的容器并运行一个命令 |
save | Save an inage to a tar archive | 保存一个镜像为一个 tar 包[对应 load] |
search | Search for an image on the Docker Hub | 在 docker hub 中搜索镜像 |
start | start a stopped containers | 启动容器 |
stop | Stop a running containers | 停止容器 |
tag | Tag an image into a repository | 给源中镜像打标签 |
top | Lookup the running processes of a container | 查看容器中运行的进程信息 |
unpause | Unpause a paused container | 取消暂停容器 |
version | Show the docker version information | 查看 docker 版本号 |
wait | Block until a container stops, then print its exit code | 戴取容器停止时的退出状态值 |
四.常用镜像入门练习
1. Docker安装Nginx
# 搜索nginx镜像,建议去docker hup上去搜索
docker search nginx
# 下载镜像
docker pull nginx
# 查看ngnix镜像是否下载成功
docker images
# 启动nginx容器
[root@node02 ~]# docker run -d --name nginx01 -p 3344:80 nginx
WARNING: IPv4 forwarding is disabled. Networking will not work.
edb9fd24ddebbc324c89f29ffbc7e54c069bcfba853ac07b1f8cf45ccd2fea1a
# 查看nginx容器
[root@node02 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
edb9fd24ddeb nginx "/docker-entrypoint.…" 17 seconds ago Up 16 seconds 0.0.0.0:3444->80/tcp nginx01
# 查看nginx服务
[root@node02 ~]# curl localhost:3344
注意:仅在宿主机上可以访问到nginx容器,而其他内网机器无法访问 http:192.168.52.110:3344
修改以下配置后可解决
# 解决办法:
vim /usr/lib/sysctl.d/00-system.conf
# 添加如下代码:
net.ipv4.ip_forward=1
# 重启network服务
systemctl restart network
# 查看是否修改成功,如果返回为“net.ipv4.ip_forward = 1”则表示成功了
sysctl net.ipv4.ip_forward
思考问题:我们每次改动nginx配置文件都需要进入容器内部,会十分麻烦。如果可以在容器外部提供一个映射路径,达到在主机修改文件,容器内部也可以自动修改就会十分便捷。后文讲的 -v数据卷可以实现此需求。
2. Docker安装Tomcat
# 官方给的示例命令如下,该命令一般用来测试,用完就会自动删除掉此容器
docker run -it --rm tomcat:9.0
# 下载官方最新镜像
docker pull tomcat
# 后台启动tomcat
docker run -d -p 3355:8080 --name tomcat01 tomcat
浏览器访问 : http://192.168.52.110:3355
结果:可以访问的到,但是返回结果是404
原因如下:
[root@node02 ~]# docker exec -it tomcat01 /bin/bash
root@dcae39a6bff5:/usr/local/tomcat# ls -al # 发现一: ll命令无法使用,说明镜像中支持的linux命令少了
total 124
drwxr-xr-x 1 root root 30 Aug 5 19:22 .
drwxr-xr-x 1 root root 20 Aug 5 19:18 ..
-rw-r--r-- 1 root root 18982 Jun 30 20:14 BUILDING.txt
-rw-r--r-- 1 root root 5409 Jun 30 20:14 CONTRIBUTING.md
-rw-r--r-- 1 root root 57092 Jun 30 20:14 LICENSE
-rw-r--r-- 1 root root 2333 Jun 30 20:14 NOTICE
-rw-r--r-- 1 root root 3255 Jun 30 20:14 README.md
-rw-r--r-- 1 root root 6898 Jun 30 20:14 RELEASE-NOTES
-rw-r--r-- 1 root root 16262 Jun 30 20:14 RUNNING.txt
drwxr-xr-x 2 root root 4096 Aug 5 19:23 bin
drwxr-xr-x 1 root root 22 Aug 25 01:37 conf
drwxr-xr-x 2 root root 4096 Aug 5 19:22 lib
drwxrwxrwx 1 root root 177 Aug 25 01:37 logs
drwxr-xr-x 2 root root 134 Aug 5 19:22 native-jni-lib
drwxrwxrwx 2 root root 30 Aug 5 19:22 temp
drwxr-xr-x 2 root root 6 Aug 5 19:22 webapps # 去webapp下看项目信息
drwxr-xr-x 7 root root 81 Jun 30 20:12 webapps.dist
drwxrwxrwx 2 root root 6 Jun 30 20:09 work
root@dcae39a6bff5:/usr/local/tomcat# cd webapps
root@dcae39a6bff5:/usr/local/tomcat/webapps# ls # 发现二: webapps下没有内容,所以返回的是404
root@dcae39a6bff5:/usr/local/tomcat/webapps# cp -r ../webapps.dist/* ./ # 复制后刷新web页面,可正常显示tomcat首页
root@dcae39a6bff5:/usr/local/tomcat/webapps# ls
ROOT docs examples host-manager manager
总结:以上问题发生的原因是, 阿里云镜像默认是最小镜像,所以镜像中不必要的内容都被剔除掉了,从而保证最小可运行环境
思考:我们以后要部署项目,如果每次都要进入容器会十分麻烦。如果可以在容器外部提供一个映射路径,webapps,我们在外部放置项目,就自动同步到内部了。
3. Docker安装Es + Kibana
docker rm -f $(docker ps -aq)
# 下载镜像
docker pull elasticsearch
# -e 修改环境配置(environment的缩写)
docker run -d --name elasticsearch01 -p 9200:9200 -p 9300:9300 -e ES_JAVA_OPTS="-Xms64m -Xmx512m" -e "discovery.type=single-node" elasticsearch
# 访问es容器
curl localhost:9200
# 查看docker的cpu和内存状况
docker stats
-e ES_JAVA_OPS="-Xms64m -Xmx512m" 增加对es的内存限制,es很占用内存
-e “discovery.type=single-node” 单节点部署环境
思考:kibana容器如何连接es容器
4. Docker安装Portainer
Portainer是Docker的图形化界面管理工具。提供一个后台面板供我们操作、监控,平时不会用。
# 安装Portainer -v 本地卷挂载,后文会讲 --privileged=true表示授权外网访问
docker run -d -p 8088:9000 \
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
五.Docker镜像讲解
1. 镜像是什么
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
所有的应用,直接打包docker镜像,就可以直接跑起来!
如何得到镜像:
- 从远程仓库下载
- 朋友拷贝给你
- 自己制作一个镜像 DockerFile
2. Docker镜像加载原理
UnionFS(联合文件系统)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
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发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs.
3. 分层理解
分层的镜像
我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层一层的在下载!
[root@node02 ~]# docker pull redis
Using default tag: latest
latest: Pulling from library/redis
bf5952930446: Already exists
911b8422b695: Pull complete
093b947e0ade: Pull complete
5b1d5f59e382: Pull complete
7a5f59580c0b: Pull complete
f9c63997c980: Pull complete
Digest: sha256:09c33840ec47815dc0351f1eca3befe741d7105b3e95bc8fdb9a7e4985b9e1e5
Status: Downloaded newer image for redis:latest
docker.io/library/redis:latest
思考:为什么Docker镜像要采用这种分层的结构呢?
最大的好处,我觉得莫过于是资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base
镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。
查看镜像分层的方式可以通过 docker image inspect
命令!分层信息保存在在layers属性中。
"Layers": [
"sha256:d0f104dc0a1f9c744b65b23b3fd4d4d3236b4656e67f776fe13f8ad8423b955c",
"sha256:09b6608896c0a00497d9e9c1b045f0c906203555740dee64473db943244059c2",
"sha256:ab0653e928a7c1d4b2f1c8e527d735aa0ea8dcb8c50e7cefc7680cf09cf6f985",
"sha256:57094a432b39be6fc8a3f533567e10c354705eec37e4f7a8b5a7041a4ec63fa2",
"sha256:1b80269d908f58520f9f3f00d75e65907eafa0f5143d5fe2b6cafcc30b32bc83",
"sha256:1bd654b55bb49880160a60ad3a75c4b14254656229d535e943d8fb88124f6177"
]
理解:
所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。
举一个简单的例子,假如基于Ubuntu Linux 16.04 创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。
该镜像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。
上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版本。
这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。
Docker 通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。
Linux 上可用的存储引擎有 AUFS、Overlay2、Device Mapper、Btrfs 以及ZFS。顾名思义,每种存储引擎都基于 Linux 中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。
Docker在Windows上仅支持windowsfilter一种存储引擎,该引基于 NTFS 文件系统之上实现了分层和CoW[1]。
下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。
特点
- Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!
- 这一层就是我们通常说的容器层,容器之下的都叫镜像层!
4. commit镜像
命令
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[tag]
测试:
[root@node02 ~]# docker rm -f $(docker ps -aq)
[root@node02 ~]# docker run -d -p 3355:8080 --name mytomcat tomcat
[root@node02 ~]# docker ps -aq
3a0d0432d1cd
[root@node02 ~]# docker exec -it mytomcat /bin/bash
root@3a0d0432d1cd:/usr/local/tomcat# cp -r webapps.dist/* webapps/
root@3a0d0432d1cd:/usr/local/tomcat# ls webapps
ROOT docs examples host-manager manager
[root@node02 ~]# docker commit -a="devin-kim" -m="tomcat webapps app docker images commit test" 3a0d0432d1cd mytomcat:1.0
sha256:67e6f4f39b6a0f9d66ac0142fd58811ff111c54bb427b6409b1d054be670643a
[root@node02 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat 1.0 67e6f4f39b6a 5 seconds ago 652MB
nginx latest 4bb46517cac3 11 days ago 133MB
centos latest 0d120b6ccaa8 2 weeks ago 215MB
tomcat latest 2ae23eb477aa 2 weeks ago 647MB
portainer/portainer latest 62771b0b9b09 4 weeks ago 79.1MB
hello-world latest bf756fb1ae65 7 months ago 13.3kB
elasticsearch latest 5acf0e8da90b 23 months ago 486MB
六.容器数据卷
如果数据存放在容器中,那么删除容器,数据也会丢失!所有,我么希望容器间有一个数据共享的技术,将Docker容器产生数据同步到本地。
于是,就产生了卷技术,用来将容器内的目录挂载到Linux上面,容器间也可以共享数据。
1. 测试
docker rm -f $(docker ps -aq)
# 命令: docker run -it -v 主机目录:容器目录 镜像名称 命令行
# 测试:
[root@node02 ~]# ls /home # 宿主机的/home目录下没有内容
[root@node02 ~]# docker run -it -v /home/ceshi:/home centos /bin/bash # 将宿主机的/home/ceshi目录与容器的/home目录映射
[root@a01f656d9ce6 /]# ls /home
[root@a01f656d9ce6 /]#
Ctrl + P + Q # 仅退出容器,容器并不会停止
[root@node02 ~]# ls /home # 宿主机的/home目录下自动创建了ceshi这个目录
ceshi
[root@node02 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a01f656d9ce6 centos "/bin/bash" 8 minutes ago Up 8 minutes busy_babbage
[root@node02 ~]# docker inspect a01f656d9ce6 # 查看此容器的元数据信息中的Mounts属性如下面的代码块
[root@node02 ~]# touch /home/ceshi/master.java
[root@node02 ~]# ls /home/ceshi/
master.java
[root@node02 ~]# docker attach a01f656d9ce6
[root@a01f656d9ce6 /]# touch /home/slave.java
[root@a01f656d9ce6 /]# ls /home
master.java slave.java
[root@a01f656d9ce6 /]# exit
exit
[root@node02 ~]# ls /home/ceshi/
master.java slave.java
[root@node02 ~]# echo "hello,I am centos OS" >> /home/ceshi/master.java
[root@node02 ~]# cat /home/ceshi/master.java
hello,I am centos OS
[root@node02 ~]# docker start a01f656d9ce6
[root@node02 ~]# docker attach a01f656d9ce6
[root@a01f656d9ce6 /]# cat /home/master.java
hello,I am centos OS
[root@a01f656d9ce6 /]# echo "hello,I am docker container" >> /home/slave.java
[root@a01f656d9ce6 /]# exit
exit
[root@node02 ~]# cat /home/ceshi/slave.java
hello,I am docker container
查看此容器的元数据信息中的Mounts属性如下面的代码块
"Mounts": [
{
"Type": "bind",
"Source": "/home/ceshi",
"Destination": "/home",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
]
注意:即使容器被删除了,宿主机上的文件也不会被删除。
2. Docker安装MySQL
获取镜像
# docker rm -f $(docker ps -aq)
docker pull mysql:5.7
测试运行:
docker run -d --name mysql01 -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/datas:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
mysql -hlocalhost -P3310 -uroot -p123456
3. 具名和匿名挂载
匿名挂载
# -P表示随机映射一个端口 -v后只指定了容器内的路径,没有指定宿主机的路径
docker run -d -P --name nginx01 -v /etc/nginx nginx
具名挂载
docker run -d -P --name nginx02 -v mynginx02:/etc/nginx nginx
运行查看区别
# docker volume --help 查看卷操作命令文档
[root@node02 mysql]# docker run -d -P --name nginx01 -v /etc/nginx nginx
0ececf091a21192a5b87402f934762d312888acdc1e3f0d9377a7fcfce4cdc83
[root@node02 mysql]# docker run -d -P --name nginx02 -v mynginx02:/etc/nginx nginx
66c3fd5a26d76f0cc2298b4ea70a7fb359ee2f00d8e8350a04255acdb9562f2c
[root@node02 mysql]# docker volume ls # 查看所有volume(卷名)
DRIVER VOLUME NAME
local 1b2981ff259408992e51580cd8d5330f0f930232baefc77acb04f3ac23d048ff
local 2e414e32e8f83f5959b86c9beb5f2711c768e73ab01585603187dc189096c939
local 5f7a668f05424aa0e87691fdbfc9fe7e038ad6262d69b7a4b6cf80a409be8b9a
local 865c4c392672a30b99a2e6e4a9360b03e35a97c23ac50cadf0540d0b5708a39b
local afe808a7164ca387dfce697fbba8e8e5dcc10b88e7feefad3e51e13ff4924631
local d8b0970a319db72b0f82794c8cdb610f404264daea41f4c923073e4868e6fc29
local e917ce3cda341e304f25b79aa56251d71e0ef3279205b4d899c71ecd4fa0e8c8
local mynginx02
[root@node02 mysql]# docker volume inspect mynginx02
[
{
"CreatedAt": "2020-08-25T16:30:02+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/mynginx02/_data",
"Name": "mynginx02",
"Options": null,
"Scope": "local"
}
]
所有docker容器内的卷,在没有指定目录的情况下都是存放在
/var/lib/docker/volumes/???/_data
目录下我们可以通过具名挂载方便的招到我们的卷,不建议使用匿名挂载
扩展:
# 通过 -v 容器内路径:ro 或者是rw,改变读写权限
ro readonly # 只读,ro说明这个路径只能通过宿主机来操作,容器内无法操作
rw readwrite # 可读、可写(默认)
# 一旦设置了容器权限,容器对我们挂在出来的内容就有限定了
docker run -d -P --name nginx03 -v mynginx03:/etc/nginx:ro nginx
docker run -d -P --name nginx04 -v mynginx04:/etc/nginx:rw nginx
4. 初识DockerFile
DockerFile是用来构建docker镜像的命令脚本文件。通过这个脚本生成一个镜像
mkdir -p /home/docker-test-volume/
vim /home/docker-test-volume/docerfile01
文件内容如下:
from centos
VOLUME ["volume01","volume02"]
CMD echo "-----end-----"
CMD /bin/bash
通过 DockerFile 定制镜像
[root@node02 home]# cd /home/docker-test-volume/
[root@node02 docker-test-volume]# docker build -f /home/docker-test-volume/docerfile01 -t mydf01-centos:1.0 .
Sending build context to Docker daemon 2.048kB
Step 1/4 : from centos
---> 0d120b6ccaa8
Step 2/4 : VOLUME ["volume01","wolume02"]
---> Running in 04869be72707
Removing intermediate container 04869be72707
---> 2781f855acbd
Step 3/4 : CMD echo "-----end-----"
---> Running in 22b99a429339
Removing intermediate container 22b99a429339
---> baa228a16e1b
Step 4/4 : CMD /bin/bash
---> Running in 373d132a75f8
Removing intermediate container 373d132a75f8
---> 3aeb4218b1e4
Successfully built 3aeb4218b1e4
Successfully tagged mydf01-centos:1.0
[root@node02 docker-test-volume]# ls
docerfile01
[root@node02 docker-test-volume]# docker images # mydf01-centos就是我们用dockerfile构建出来的镜像
REPOSITORY TAG IMAGE ID CREATED SIZE
mydf01-centos 1.0 3aeb4218b1e4 17 seconds ago 215MB
mytomcat 1.0 67e6f4f39b6a 4 hours ago 652MB
[root@node02 docker-test-volume]# docker run -it 3aeb4218b1e4 /bin/bash
[root@45c6ca19e300 /]# ls -l
total 0
lrwxrwxrwx 1 root root 7 May 11 2019 bin -> usr/bin
drwxr-xr-x 5 root root 360 Aug 25 10:13 dev
drwxr-xr-x 1 root root 66 Aug 25 10:13 etc
drwxr-xr-x 2 root root 6 May 11 2019 home
lrwxrwxrwx 1 root root 7 May 11 2019 lib -> usr/lib
lrwxrwxrwx 1 root root 9 May 11 2019 lib64 -> usr/lib64
drwx------ 2 root root 6 Aug 9 21:40 lost+found
drwxr-xr-x 2 root root 6 May 11 2019 media
drwxr-xr-x 2 root root 6 May 11 2019 mnt
drwxr-xr-x 2 root root 6 May 11 2019 opt
dr-xr-xr-x 128 root root 0 Aug 25 10:13 proc
dr-xr-x--- 2 root root 162 Aug 9 21:40 root
drwxr-xr-x 11 root root 163 Aug 9 21:40 run
lrwxrwxrwx 1 root root 8 May 11 2019 sbin -> usr/sbin
drwxr-xr-x 2 root root 6 May 11 2019 srv
dr-xr-xr-x 13 root root 0 Aug 25 10:13 sys
drwxrwxrwt 7 root root 145 Aug 9 21:40 tmp
drwxr-xr-x 12 root root 144 Aug 9 21:40 usr
drwxr-xr-x 20 root root 262 Aug 9 21:40 var
drwxr-xr-x 2 root root 6 Aug 25 10:13 volume01 # 这是生成镜像时自动挂载的匿名数据卷目录
drwxr-xr-x 2 root root 6 Aug 25 10:13 volume02 # 对应dockerfile01中的 VOLUME ["volume01","volume02"]
[root@45c6ca19e300 /]# echo "I am volume01" >> /volume01/myfile.txt
[root@45c6ca19e300 /]# ls /volume01/
myfile.txt
[root@45c6ca19e300 /]# exit
exit
[root@node02 docker-test-volume]# docker inspect 45c6ca19e300 # 查看 Mounts 的属性值,如下代码块
查看到的卷挂载路径如下
"Mounts": [
{
"Type": "volume",
"Name": "902971cdd33038d6ce43db14c00c56bbb17decfb1b13fcdacd64ee8c9bfc2c5c",
"Source": "/var/lib/docker/volumes/902971cdd33038d6ce43db14c00c56bbb17decfb1b13fcdacd64ee8c9bfc2c5c/_data",
"Destination": "volume02",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "volume",
"Name": "f7dc222ae6e0973da4b6680ba419b84d9c7f4bfaf7fddbe7955906779f4bee87",
"Source": "/var/lib/docker/volumes/f7dc222ae6e0973da4b6680ba419b84d9c7f4bfaf7fddbe7955906779f4bee87/_data",
"Destination": "volume01",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
]
# 查看文件是否已经同步到宿主机了
[root@node02 _data]# cat /var/lib/docker/volumes/f7dc222ae6e0973da4b6680ba419b84d9c7f4bfaf7fddbe7955906779f4bee87/_data/myfile.txt
I am volume01
5. 数据卷容器
实现多个mysql容器间的数据的同步
docker rm -f $(docker ps -aq)
docker run -it --name docker01 mydf01-centos:1.0
docker run -it --name docker02 --volumes-from docker01 mydf01-centos:1.0
# 然后在 docker01的volume01目录下创建文件,也会同步到docker02的volume01目录下。删了docker01数据也不会丢失
docker run -d --name mysql02 -p 3310:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
docker run -d --name mysql03 -p 3310:3306 --volumes-from mysql02 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
结论:
- 数据卷容器的声明周期一直持续到没有容器使用为止
- 一旦持久化到本地,本地的数据是不会删除的
七.DockerFile
1. DockerFile简介
DockerFile是用来构建docker镜像的的文件!命令参数脚本。
构建步骤:
- 编写一个dockerfile文件
- docker build构建成为一个镜像
- docker run 运行镜像
- docker push发布镜像(如:DockerHub、阿里云镜像仓库)
step1:进入docker hub查找centos镜像,点击centos7这个tag
step2:跳转到了git hub中,内容是一个dockerfile
step3:获取到的dockerfile的内容如下
Docker hub中,99%镜像都是在这个基础镜像来FROM Search,然后配置需要的软件和配置来进行构建
FROM scratch
ADD centos-7-x86_64-docker.tar.xz /
LABEL \
org.label-schema.schema-version="1.0" \
org.label-schema.name="CentOS Base Image" \
org.label-schema.vendor="CentOS" \
org.label-schema.license="GPLv2" \
org.label-schema.build-date="20200809" \
org.opencontainers.image.title="CentOS Base Image" \
org.opencontainers.image.vendor="CentOS" \
org.opencontainers.image.licenses="GPL-2.0-only" \
org.opencontainers.image.created="2020-08-09 00:00:00+01:00"
CMD ["/bin/bash"]
从上述官方镜像都是基础包,很多功能都没有(如jdk,redis等),我们通常会自己搭建自己的镜像。
2. DockerFile构建过程
- 每个指令(又叫:保留关键字),都必须是大写字母
- 顺序执行
- 使用 # 表示注释
- 每一个指令都会创建提交一个新的镜像层
Dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件,这个文件十分简单
Docker镜像已经 成为了企业交互的标准,所以必须要掌握这部分内容
Dockerfile:构建文件,定义了一切的步骤,类似于源代码
DockerImage:镜像,通过Dockerfile构建生成的镜像,最终发布和运行的产品,类似于原来的war包
DockerContrainer:容器,就是镜像运行起来提供服务
3. DockerFile的指令
以前都是使用别人的镜像,现在通过下面的命令生成自己的DockerFile,构建自己的镜像
指令 | 说明 |
---|---|
FROM | 设置镜像使用的基本镜像 |
MAINTAINER | 设置镜像的作者,常用:姓名+邮箱 |
RUN | 设置构建镜像时要运行的命令 |
ADD | 设置构建镜像时要复制到镜像中的文件,会自动解压 |
COPY | 设置构建镜像时要复制到镜像中的文件,不会自动解压 |
WORKDIR | 设置RUN CMD ENTRYPOINT COPY ADD指令的工作目录 |
VOLUME | 设置容器的挂载卷,挂载的主机目录 |
EXPOSE | 设置镜像暴露的端口 |
CMD | 设置容器启动时要运行的命令,只有最后一个会生效,可被替代 |
ENTRYPOINT | 设置容器启动时要运行的命令,可以追加命令 |
ONBUILD | 当构建一个被继承 DockerFile时,运行ONBUILD的指令,触发指令 |
ENV | 设置容器的环境变量 |
USER | 设置运行RUN CMD ENTRYPOINT的用户名 |
ARG | 设置编译镜像时加入的参数 |
LABEL | 设置镜像的标签 |
STOPSIGNAL | 设置容器的退出信号量 |
4. 实战测试
4.1 编写dockerfile文件
vim /home/dcokerfile-20200826-01
# 设置镜像使用的基本镜像
FROM centos
# 设置镜像的作者,常用:姓名+邮箱
MAINTAINER devin-kim<13770473170@163.com>
# 设置容器的环境变量
ENV MYPATH /usr/local
# 设置RUN CMD ENTRYPOINT COPY ADD指令的工作目录
WORKDIR $MYPATH
# 设置构建镜像时要运行的命令
RUN yum -y install vim
RUN yum -y install net-tools
# 设置镜像暴露的端口
EXPOSE 80
# 设置容器启动时要运行的命令,只有最后一个会生效,可被替代
CMD echo $MYPATH
CMD echo "--------end------"
CMD /bin/bash
4.2 构建镜像
docker build -f /home/dcokerfile-20200826-01 -t my-centos-01:1.0 .
4.3 测试运行
[root@node02 ~]# docker run -it my-centos-01:1.0
[root@52b24dfb0b9b local]# pwd # 直接进入到了工作目录,因为文件中定义了WORKDIR $MYPATH
/usr/local
[root@52b24dfb0b9b local]# vim aaa # 可正常使用,说明 RUN yum -y install vim 生效了
[root@52b24dfb0b9b local]# ifconfig # 可正常使用,说明 RUN yum -y install net-tools 生效了
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:ac:11:00:02 txqueuelen 0 (Ethernet)
RX packets 8 bytes 656 (656.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
4.4 查看镜像构建过程
控制台日志显示了镜像的构建步骤,
[root@node02 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
my-centos-01 1.0 d91ba57f8da9 11 minutes ago 295MB
... ...
[root@node02 ~]# docker history d91ba57f8da9
IMAGE CREATED CREATED BY SIZE COMMENT
d91ba57f8da9 12 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/bin… 0B
a05dfbb78a0d 12 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "echo… 0B
9e8f1d61cf65 12 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "echo… 0B
c269cf868f07 12 minutes ago /bin/sh -c #(nop) EXPOSE 80 0B
4359a7a1b9b8 12 minutes ago /bin/sh -c yum -y install net-tools 22.8MB
5aeac9e3857c 12 minutes ago /bin/sh -c yum -y install vim 57.2MB
79ff8a171068 12 minutes ago /bin/sh -c #(nop) WORKDIR /usr/local 0B
125ba0dad671 12 minutes ago /bin/sh -c #(nop) ENV MYPATH=/usr/local 0B
f0c86ca7f102 12 minutes ago /bin/sh -c #(nop) MAINTAINER devin-kim<1377… 0B
0d120b6ccaa8 2 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 2 weeks ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ADD file:538afc0c5c964ce0d… 215MB
4.5 CMD和ENTRYPOINT的区别
CMD
vim /home/dcokerfile-cmd-test
FROM centos
CMD ["ls","-a"]
docker build -f /home/dcokerfile-cmd-test -t cmd-test:1.0 .
docker run cmd-test:1.0
# 运行下面的命令会报错
[root@node02 ~]# docker run cmd-test:1.0 -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"-l\": executable file not found in $PATH": unknown.
ERRO[0000] error waiting for container: context canceled
错误原因:
-l
命令替换掉了dockerfile中CMD ["ls","-a"]
定义的ls -a
命令,在centos客户端只执行-l
,所以会报错。
ENTRYPOINT
vim /home/dcokerfile-entrypoint-test
FROM centos
ENTRYPOINT ["ls","-a"]
docker build -f /home/dcokerfile-entrypoint-test -t entrypoint-test:1.0 .
docker run entrypoint-test:1.0
# 下面的命令可正常执行
docker run entrypoint-test:1.0 -l
正常执行是因为ENTRYPOINT可以实现将
-l
与ls -a
做了拼接,实际执行的是ls -a -l
4.6 构建Tomcat镜像
下载jdk和tomcat安装包,可使用下面的链接。上传压缩包到/home/tomcat
目录下
链接:https://pan.baidu.com/s/1ja7R-iqFz8U9K-SW_6G1lw
提取码:18bs
echo "I am readme file" >> /home/tomcat/readme.txt
vim /home/tomcat/Dockerfile
# 设置镜像使用的基本镜像
FROM centos
# 设置镜像的作者,常用:姓名+邮箱
MAINTAINER devin-kim<13770473170@163.com>
# 复制宿主机此dockerfile目录下的readme.txt文件到容器/usr/local/readme.txt
COPY readme.txt /usr/local/readme.txt
# 设置构建镜像时要复制到镜像中的文件,会自动解压
ADD jdk-8u231-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-8.5.56.tar.gz /usr/local/
# 设置构建镜像时要运行的命令
RUN yum -y install vim
# 设置容器的环境变量
ENV MYPATH /usr/local
# 设置RUN CMD ENTRYPOINT COPY ADD指令的工作目录
WORKDIR $MYPATH
# java和tomcat的环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_231
ENV CLASSPATH $JAVA_HOME/lib/dt.jar;$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.56
ENV CATALINA_BASH /usr/local/apache-tomcat-8.5.56
ENV PATH $PATH;$JAVA_HOME/bin;$CATALINA_lib;$CATALINA_HOME/bin
# 设置镜像暴露的端口
EXPOSE 8080
# 设置容器启动时要运行的命令,只有最后一个会生效,可被替代
CMD /usr/local/apache-tomcat-8.5.56/bin/startup.sh && tail -F /usr/local/apache-tomcat-8.5.56/logs/catalina.out
构建镜像
cd /home/tomcat
docker build -t my-tomcat .
上述命令有多个细节:
- 在此dockerfile所在的目录执行的此命令
- 当dockerfile的文件名为Dockerfile是,可省略
-f dockerfile文件名
命令行- 未指定my-tomcat的Tag,默认生成的tag是
latest
启动容器
# 运行后浏览器可正常访问: http://192.168.52.110:9090/
docker run -d -p 9090:8080 --name mytomcat-cn01 \
-v /home/jyx/test:/usr/local/apache-tomcat-8.5.56/webapps/test \
-v /home/jyx/tomcatlogs:/usr/local/apache-tomcat-8.5.56/logs \
my-tomcat
启动容器是设置了两个卷挂载,我们可以在宿主机的/home/jyx/tomcatlogs
去查看tomcat的日志信息,在/home/jyx/test
本地编写项目发布到容器中的tomcat
mkdir -p /home/jyx/test/WEB-INF
vim /home/jyx/test/WEB-INF/web.xml # 文件内容为下一个代码块
vim /home/jyx/test/index.jsp # 文件内容为下面第二个代码块
# 创建好文件后访问 http://192.168.52.110:9090/test/index.jsp
以下是web.xml文件的内容
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
</web-app>
以下是index.jsp文件的内容
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>首页</title>
</head>
<body>
<div class="header">
<div class="logo">web实践</div>
<div class ="login">
<a href ="javascript:void(0)">登录</a>
<span>|</span>
<a href ="javascript:void(0)">故事</a>
</div>
</div>
</body>
</html>
去/home/lxh/tomcatlogs
目录下查看tomcat访问日志:catalina.out
tail -f /home/jyx/tomcatlogs/catalina.out
5. 发布镜像
将镜像提交到Docker Hub
# 1、在地址https://hub.docker.com/中注册一个自己的账号
# 2、在邮箱确认后,保证这个账号能正常登陆的。
# 3、使用注册的Docker ID和密码,登录docker,
docker login -u 627574775
# 4、给镜像添加版本号 命令: docker tag 镜像id dockerhub账号的id/镜像名称:版本号
docker tag 3b75b9eb8e10 627574775/my-tomcat:1.0
# 5、带上版本号后重新提交 # 最终还是失败了,报错:denied: requested access to the resource is denied。可能是网络问题,后面再解决
docker push 627574775/my-tomcat:1.0
注意:第4步,必须要吧dockerhub账号的id作为前缀加上
/
再加上镜像名称,要不会报错。
将镜像发布到阿里云镜像服务
-
登陆阿里云;
-
找到容器镜像服务;
-
新建一个命名空间,再创建一个镜像容器;
-
在镜像仓库菜单创建私有的本地仓库;
-
查看创建的仓库,里面的步骤十分详细。【注意:复制阿里云网页文字时,可能会存在特殊字符,最好先粘贴到nodepad++上面】
6. 小结
八.Docker网络
1. 理解docker0
# 学习前,先清空镜像库,重头开始学习
docker rmi -f $(docker images -aq)
查看宿主机ip地址发现了3个网卡,如下
然后,我们启动一个tomcat容器
docker run -d -P --name tomcat01 tomcat
查看tomcat容器的ip地址
[root@node02 tomcat]# docker exec -it tomcat01 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
92: eth0@if93: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 172.17.0.2这个网络地址和宿主机172.17.0.1在同一网段,说明这两个ip都是由docker0网卡分配的
# 容器内ping 172.17.0.1 可以ping通
# 宿主机ping 172.17.0.2 可以ping通
# 容器内ping www.baidu.com 可以ping通
结论一: 只要装了docker,就会给宿主机安装docker0网卡。每启动一个docker容器,docker就会给docker容器分配一个ip。
tomcat01容器运行后,我们重新查看宿主机ip地址,会发现多了一个网卡,如下
[root@node02 tomcat]#
[root@node02 tomcat]# ip addr # 多出的网卡如下
93: veth51fac72@if92: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether ee:f6:28:36:83:cb brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::ecf6:28ff:fe36:83cb/64 scope link
valid_lft forever preferred_lft forever
# 对比这个网卡和tomcat01容器的网卡,发现很相似,如下:
# 92: eth0@if93 93: veth51fac72@if92
# 再启动一个tomcat02容器,发现宿主机又多了一个网卡
[root@node02 tomcat]# docker run -d -P --name tomcat02 tomcat
[root@node02 tomcat]# ip addr # 又多出了一块网卡
95: veth094e059@if94: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 7e:e1:54:94:f7:4c brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::7ce1:54ff:fe94:f74c/64 scope link
valid_lft forever preferred_lft forever
[root@node02 tomcat]# docker exec -it tomcat02 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
94: eth0@if95: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# tomcat01容器和tomcat02容器也是可以ping通的
总结:我们发现容器带来的网卡都是一对一对出现的,这是桥接模式中的evth-pair技术
evth-pair就是一对的虚拟设备接口,成对出现,一段连接着协议,一段彼此相连
只要容器删除,对应的一对网桥就没了
2. 命令行参数 --link
**问题:**我们启动的两个tomcat容器服务的名字分别是:tomcat01、tomcat02,那么能不能在tomcat01容器t通过ping tomcat02
与tomcat02通信呢?
测试:
[root@node02 ~]# docker exec -it tomcat01 /bin/bash
root@fd046d49f073:/usr/local/tomcat# ping tomcat02
ping: tomcat02: Name or service not known
结果:无法ping通,那么如何通过容器的服务名与tomcat02通信呢?
# 使用 --link 命令行参数从新启动一个容器tomcat03
[root@node02 ~]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
4798103ff67effc462c17846feaa6cb45b46715b3d35045c7eac5cbb4f3ef3d7
[root@node02 ~]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.079 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.042 ms
[root@node02 ~]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known
启动tomcat03容器时添加--link tomcat02
后tomcat03容器可以ping通tomcat02容器,但tomcat02容器无法ping通tomcat03容器,因为启动tomcat02容器的时候没有用–link配置。原因分析如下:
查看tomcat03的元数据信息,发现了其中的多了一个Links属性,如下
[root@node02 ~]# docker inspect tomcat03 # Link属性内容如下
"Links": [
"/tomcat02:/tomcat03/tomcat02"
]
分别使用上面两个命令查看/etc/hosts文件,发现tomcat03容器的hosts文件多了一行配置172.17.0.3 tomcat02 393d9b624b57
,所以,link命令行参数的本质是在容器的hosts文件中添加一行ip地址与容器服务名的映射,现在已不推荐这种使用方式了。
docker exec -it tomcat02 cat /etc/hosts
docker exec -it tomcat03 cat /etc/hosts
3. 自定义网络
查看所有的docker网络
[root@node02 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
1ffc06514dd2 bridge bridge local
76598b4f6f5e host host local
1b457516b387 none null local
# 查看 1ffc06514dd2 bridge 的详细元数据信息
[root@node02 ~]# docker network inspect 1ffc06514dd2
Docker支持的网络模式:
- bridge : 桥接(默认)
- none : 不配置网络
- host : 和宿主机共享网络
- container : 容器内网络连通(很少用,局限性大)
创建一个网络
# 先清空现有容器
docker rm -f $(docker ps -aq)
# 我们之前启动容器,没有指定 --net 命令行参数,即,使用的是 --net bridge 这个默认值,就是docker0
# dcoker0是有弊端的:默认情况下不能使用容器服务名相互通信,要写连通只能使用--link指定,很麻烦
# 所以,我们要自定义一个网络,默认就实现了容器间通过容器服务名通信
docker network create --driver bridge --subnet 10.90.0.0/16 --gateway 10.90.0.1 mynet
–driver bridge 网络模式,默认就是bridge
–subnet 192.168.0.0/16 子网
–gateway 192.168.0.1 网关
mynet 创建的网络的名称
查看创建的网络
docker network ls
docker network inspect mynet
# 查看宿主机ip也多了一块网卡
[root@node02 ~]# ip addr
98: br-50257d18e2ae: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:c8:9e:55:a4 brd ff:ff:ff:ff:ff:ff
inet 10.90.0.1/16 brd 10.90.255.255 scope global br-50257d18e2ae
valid_lft forever preferred_lft forever
inet6 fe80::42:c8ff:fe9e:55a4/64 scope link
valid_lft forever preferred_lft forever
测试
docker rm -f $(docker ps -aq)
# 使用mynet网略启动
docker run -d -P --name tomcat-mynet-01 --net mynet tomcat
docker run -d -P --name tomcat-mynet-02 --net mynet tomcat
docker run -d -P --name tomcat-mynet-03 --net mynet tomcat
# 测试使用容器服务名相互通信 结果,可以相互ping通
docker exec -it tomcat-mynet-01 ping tomcat-mynet01-02
docker exec -it tomcat-mynet-01 ping tomcat-mynet01-03
docker exec -it tomcat-mynet-02 ping tomcat-mynet01-03
# 查看容hosts,无ip映射
docker exec -it tomcat-mynet-01 cat /etc/hosts
自定义网络的优点
不同的集群使用不同的网络可以实现集群间网路隔离,保证网络的安全。比如:redis集群使用10.90网段,mysql集群使用10.91网段,两个网段间默认是不能通信的,从而保证了两个集群间的网络安全。那么,如果就想让这两个网段间相互通信,又该怎么做呢?
4. 网络连通
目前宿主机上有docker0和mynet两个网络,接下来要实现的就是:让*使用docker0网络的容器* 和 使用mynet网络的容器相互通信。
[root@node02 ~]# docker network --help # 注意有一个connect命令行参数
Usage: docker network COMMAND
Manage networks
Commands:
connect Connect a container to a network # 连接一个容器到一个网络
... ...
[root@node02 ~]# docker network connect --help # 查看如何使用
Usage: docker network connect [OPTIONS] NETWORK CONTAINER
Connect a container to a network
Options:
--alias strings Add network-scoped alias for the container
--driver-opt strings driver options for the network
--ip string IPv4 address (e.g., 172.30.100.104)
--ip6 string IPv6 address (e.g., 2001:db8::33)
--link list Add link to another container
--link-local-ip strings Add a link-local address for the container
测试
# 使用docker0网络启动容器tomcat01
docker run -d -P --name tomcat01 tomcat
# 将tomcat01容器连接到mynet网络
docker network connect mynet tomcat01
# 连接测试,可以相互通信
docker exec -it tomcat-mynet-01 ping tomcat01
docker exec -it tomcat01 ping tomcat-mynet-01
# 查看mynet网络信息,发现"Containers"属性下多了一个容器,就是tomcat01,也就是说,mynet网络给tomcat01也分配了一个10.90网段的ip
docker network inspect mynet
# tomcat01容器多了一个10.90网段的网卡
docker exec -it tomcat01 ip addr
5. Docker安装Redis集群
部署要求:分片+高可用+负载均衡
集群规划:6台容器主从关系如下表
主节点容器名 | 从节点容器名 |
---|---|
redis-1 | redis-4 |
redis-2 | redis-5 |
redis-3 | redis-6 |
创建redis集群的专用网络
docker rm -f $(docker ps -aq)
docker network create redis --subnet 172.38.0.0/16
通过脚本创建六个redis服务的配置文件
for port in $(seq 1 6);\
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
启动redis容器
for num in $(seq 1 6);\
do \
docker run -p 637${num}:6379 -p 1637${num}:16379 --name redis-${num} \
-v /mydata/redis/node-${num}/data:/data \
-v /mydata/redis/node-${num}/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.1${num} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
done
进入redis-1容器创建集群
# redis容器中没有/bin/bash脚本,要用/bin/sh进入
[root@node02 conf]# docker exec -it redis-1 /bin/sh
# 创建redis集群
/data # redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
# 进入redis集群客户端
/data # redis-cli -c
# 查看redis集群的基本信息
127.0.0.1:6379> cluster info
# 查看redis集群的节点信息
127.0.0.1:6379> cluster nodes
测试高可用
# 停掉resis-3容器,再查看redis集群的节点信息会发现有一个原本为slaver的redis容器变成了master
docker stop redis-3
查看docker容器的资源使用状况,发现redis集群很节省资源
[root@node02 ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
13d19739c036 redis-6 0.17% 16.37MiB / 3.682GiB 0.43% 8.2MB / 8.2MB 0B / 0B 4
1d0e300740f1 redis-5 0.21% 12.35MiB / 3.682GiB 0.33% 8.12MB / 8.12MB 0B / 0B 4
4462a02cef92 redis-4 0.12% 12.38MiB / 3.682GiB 0.33% 8.12MB / 8.11MB 0B / 0B 4
69251ff3379b redis-3 0.21% 12.25MiB / 3.682GiB 0.32% 2.49MB / 2.47MB 0B / 0B 4
4a4852b47daf redis-2 0.15% 8.438MiB / 3.682GiB 0.22% 8.26MB / 8.14MB 0B / 0B 4
5d2395a8f25b redis-1 0.16% 8.582MiB / 3.682GiB 0.23% 8.19MB / 8.21MB 0B / 0B 5
6. SpringBoot微服务打包成docker镜像
写一个简单的springboot接口测试程序上传到/home/app01
目录下
docker rm -f $(docker ps -aq)
mkdir -p /home/app01/
cd /home/app01/
# 编写Dockerfile文件,下面的代码块是文件内容
vim /home/app01/Dockerfile
FROM java:8
COPY docker-test-0.1.0.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
编译、运行镜像
cd /home/app01/
docker build -t myapp:0.1.0 .
docker run -d -p 9090:8080 --name datavis-web myapp:0.1.0
#测试
curl localhost:9090/test
九.Docker Compose
Docker Compose 批量容器编排服务
官方文档:https://docs.docker.com/compose/
1. 官网简介
Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration. To learn more about all the features of Compose, see the list of features.【 Compose是定义、运行多个容器的一个管理工具,通过yaml文件来配置你的服务,使用一个简单的命令就能启动所有的服务。】
Compose works in all environments: production, staging, development, testing, as well as CI workflows. You can learn more about each case in Common Use Cases.【所有的环境都可使用Compose】
Using Compose is basically a three-step process:【使用compose主要有三个基本步骤】
- Define your app’s environment with a
Dockerfile
.【使用Dockerfile定义应用程序的环境】 - Define the services that make up your app in
docker-compose.yml
so they can be run together in an isolated environment. - Run
docker-compose up
and Compose starts and runs your entire app.
2. 安装compose
docker rm -f $(docker ps -aq)
docker rmi -f $(docker images -aq)
# 官方下载下载compose 下载很慢,不推荐使用
curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 从国内网站下载
curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.5/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
# 给下载的文件授权
chmod +x /usr/local/bin/docker-compose
# 查看是否安装成功
docker-compose version
3. 官网快速入门案例
https://docs.docker.com/compose/gettingstarted/
mkdir -p /home/compose
cd /home/compose
# 创建一个文件名为app.py的Python应用,下个代码块是内容
vim app.py
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
@app.route('/')
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.\n'.format(count)
# 创建 requirements.txt 文件
vim requirements.txt # 文件内容如下
flask
redis
# 创建 Dockerfile 文件,下个代码块是内容
vim Dockerfile
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP app.py
ENV FLASK_RUN_HOST 0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]
# 创建 docker-compose.yml 文件,下个代码块是内容
vim docker-compose.yml
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"
# 使用Compose构建和运行服务,运行成功后可访问 curl localhost:5000
cd /home/compose # 要在yaml文件所在的目录下运行
docker-compose up
总结上述步骤:
- 开发应用 app.py
- 使用Dockerfile将应用打包为镜像
- 配置docker-compose.yml文件,(定义整个服务、需要的环境:web和redis)
- 启动compose项目
观察
compose
启动的容器,容器名是默认生成的,而且还默认生成了一个网络
4. yaml文件编写规则
compose 文件是一个定义服务、网络和卷的YAML文件。【官方文档、百度上资料和示例文件很多】
version: "3" #docker版本,会向下兼容
services: #服务
redis: #第一个服务
image: redis:alpine #镜像名: 仓库/标签:版本
ports: #暴露端口信息
- "6379"
#添加环境变量.可以使用数组或字典两种形式
#任何布尔值:true, false, yes, no 需要用引号括起来,以确保它们不被YAML解析器转换为True或False
environment:
db: #第二个服务
image: postgres:9.4
# 定义全局挂载卷
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
deploy:
placement:
constraints: [node.role == manager]
5. Compose一键部署WP博客
https://docs.docker.com/compose/wordpress/
mkdir -p /home/wp
cd /home/wp
vim /home/wp/docker-compose.yml
version: '3.3'
services:
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
db_data: {}
# 一键启动。启动后,访问8000端口
cd /home/wp
docker-compose up -d
十.Docker Swarm
官网:https://docs.docker.com/engine/swarm/
强烈建议参照:https://www.cnblogs.com/zhujingzhi/p/9792432.html 学习,课程讲的不太细致
虚拟机节点规划
主机名 | 内网IP | 工作模式 | CPU | MEM |
---|---|---|---|---|
node02.hadoop.com | 192.168.52.110 | manager | 2Core | 4GB |
node03.hadoop.com | 192.168.52.120 | manager | 2Core | 4GB |
node04.hadoop.com | 192.168.52.130 | worker | 2Core | 4GB |
1. 工作模式
Docker Engine 1.12 introduces swarm mode that enables you to create a cluster of one or more Docker Engines called a swarm. A swarm consists of one or more nodes: physical or virtual machines running Docker Engine 1.12 or later in swarm mode.
There are two types of nodes: managers and workers.
If you haven’t already, read through the swarm mode overview and key concepts.
2. 搭建集群
帮助命令:docker swarm --help
在node02主机:初始化节点
# 注意控制台日志:如果要把一个worker节点加入到这个swarm中使用下面的命令 --> 等会在node04主机执行
[root@node02 ~]# docker swarm init --advertise-addr 192.168.52.110
Swarm initialized: current node (cxc47cw7zz2mprrm55jtsdsux) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-6ch6e4kzbos046etjeqt0fkh2fd4b59fpre4nres3z5mi6ea3d-2tfn5oi3vf080fdf98fd3hho4 192.168.52.110:2377
# 注意控制台日志:如果要把一个worker节点加入到这个swarm中,先使用 docker swarm join-token manager 命令,生成shell命令 --> 等会在node03主机执行
[root@node02 ~]# docker swarm join-token manager
To add a manager to this swarm, run the following command:
docker swarm join --token SWMTKN-1-6ch6e4kzbos046etjeqt0fkh2fd4b59fpre4nres3z5mi6ea3d-amuelt21g29yon7p27drfbuba 192.168.52.110:2377
初始化节点:
docker swarm init
加入一个节点:
docker swarm join
获取节点令牌:
docker swarm join-token manager
、docker swarm join-token worker
在node04主机:将node04主机作为worker节点加入swarm
[root@node04 ~]# docker swarm join --token SWMTKN-1-6ch6e4kzbos046etjeqt0fkh2fd4b59fpre4nres3z5mi6ea3d-2tfn5oi3vf080fdf98fd3hho4 192.168.52.110:2377
This node joined a swarm as a worker.
在node03主机:将node03主机作为manager节点加入swarm
[root@node03 ~]# docker swarm join --token SWMTKN-1-6ch6e4kzbos046etjeqt0fkh2fd4b59fpre4nres3z5mi6ea3d-amuelt21g29yon7p27drfbuba 192.168.52.110:2377
This node joined a swarm as a manager.
在node01主机:查看节点状态
[root@node02 ~]# docker node ls # docker swarm的管理命令只能在manager节点执行
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
cxc47cw7zz2mprrm55jtsdsux * node02.hadoop.com Ready Active Leader 19.03.12
5x2ky16u31b5gauxsvpbbf8ti node03.hadoop.com Ready Active Reachable 19.03.12
9c7v4stp9hymc78if7r4usbug node04.hadoop.com Ready Active 19.03.12
3. Raft协议
Raft协议是一种分布式一致性协议。结合docker swarm的使用简单理解为:只有保证集群中manager节点的存活数量>1,集群才可用,所以,通常集群中manager的数量要>=3。
测试:
-
将node02主机上的docker停掉,此时存活的manager节点只有node03这一台,数量不足两台,swarm集群就不能使用了。
[root@node02 ~]# systemctl stop docker [root@node03 ~]# docker node ls Error response from daemon: rpc error: code = Unknown desc = The swarm does not have a leader. It's possible that too few managers are online. Make sure more than half of the managers are online. [root@node02 ~]# systemctl start docker # 重启docker后发现leader节点成了node03
-
将node04从swarm集群中移除,再作为一个manager节点重新加入
[root@node04 ~]# docker swarm leave # 如果是manager 要在使用 docker swarm leave --force [root@node03 ~]# docker node ls #查看节点状态发现node04状态为Down [root@node03 ~]# docker swarm join-token manager [root@node04 ~]# docker swarm join --token SWMTKN-1-6ch6e4kzbos046etjeqt0fkh2fd4b59fpre4nres3z5mi6ea3d-amuelt21g29yon7p27drfbuba 192.168.52.120:2377 This node joined a swarm as a manager. [root@node03 ~]# docker node ls #查看节点状态发现node04状态为Down
4. 弹性扩缩容
先重建一下docker swarm集群:
- 在三台主机分别执行
docker swarm leave --force
命令 - 重复 10.2章节 - 搭建集群 的操作
[root@node02 ~]# docker service --help
Usage: docker service COMMAND
Manage services
Commands:
create Create a new service
inspect Display detailed information on one or more services
logs Fetch the logs of a service or task
ls List services
ps List the tasks of one or more services
rm Remove one or more services
rollback Revert changes to a service's configuration
scale Scale one or multiple replicated services
update Update a service
Run 'docker service COMMAND --help' for more information on a command.
入门案例:
[root@node02 ~]# docker network create -d overlay nginx_net # 这样swarm集群的所有节点有创建了这个网络
[root@node02 ~]# docker service create --network nginx_net -p 8888:80 --name nginx01 nginx
docker run
和docker service
的区别:
docker run
启动容器,不具有扩缩容器的功能;docker service
启动服务,具有扩缩容器、滚动更新的功能
[root@node02 ~]# docker service ls # 注意,只有一个副本(即,实际只启动了一个容器)
ID NAME MODE REPLICAS IMAGE PORTS
qyxg2tikq1fx nginx01 replicated 1/1 nginx:latest *:8888->80/tcp
# 分别在 3 台主机上使用docker ps 发现只有node04节点上运行了一个容器
[root@node03 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b8f22f457cc2 nginx:latest "/docker-entrypoint.…" 12 minutes ago Up 12 minutes 80/tcp nginx01.1.lvcbtaxpy86h0bggdlpkr0ruc
副本是用来干什么用的呢?
- 当访问量特别大的时候,一台nginx容器压力很大,可能无法处理,大量请求。我们可以通过增加nginx01的副本数量来解决这个问题
[root@node03 ~]# docker service update --replicas 3 nginx01 # 可以使用这个命令再把副本数改为1,这就是动态扩缩容
nginx01
overall progress: 3 out of 3 tasks
1/3: running [==================================================>]
2/3: running [==================================================>]
3/3: running [==================================================>]
verify: Service converged
[root@node03 ~]# curl localhost:8888
^C
[root@node03 ~]# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
qyxg2tikq1fx nginx01 replicated 3/3 nginx:latest *:8888->80/tcp
# 分别在 3 台主机上使用docker ps 发现三台主机运行了一个容器
总结:
- 服务可以使用swarm的任意一个节点的IP + 端口号去访问。 <暂时没实现,暂未找到具体原因。。。>
- 服务可以有多个副本,动态的去扩缩容,从而实现服务的高可用和服务器的高可用(如:阿里云)。未来可以使用k8s实现。
十一.Docker Stack
待学习
十二.Docker Secret
待学习
十三.Docker Config
待学习
更多推荐
所有评论(0)