Docker解密

Docker 平台的基本构成

安装Docker

环境准备

1、需要会一点点Linux基础

2、CentOS 7

3、Xshell 或者其它远程连接工具

环境查看

# 查看系统内核, 要求版本>3.10
uname -r
3.10.0-1062.12.1.el7.x86_64
# 查看系统版本等相关信息
cat /etc/os-release

安装

帮助文档:

# 1. 卸载旧的版本
yum remove docker \
	docker-client \
	docker-client-latest \
	docker-common \
	docker-latest \
	docker-latest-logrotate \
	docker-engine
# 2. 安装依赖包
yum install -y yum-untils
# 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 社区版  docker-ee 企业版
yum install docker-ce docker-ce-cli containerd.io
# 安装指定版本
yum install docker-ce-<VERSION-STRING> docker-ce-cli-<VERSION-STRING> container.io
# 5. 启动Docker
systemctl start docker
# 6. 使用docker version查看是否安装成功
docker version
# 7. 测试 HelloWorld!
docker run hello-world
# 8. 查看已下载的镜像
docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
hello-world   latest    d1165f221234   5 months ago   13.3kB

卸载docker

# 1. 卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
# 2. 删除资源
rm -rf /var/lib/docker # Docker的默认工作资源路径

安装-2

RedHat/CentOS必须要6.6版本以上,或者7.x才能安装docker,建议在RedHat/CentOS 7上使用docker,因为RedHat/CentOS 7的内核升级到了kernel 3.10,对lxc容器支持更好。

查看Linux内核版本(内核版本必须是3.10或者以上):

cat /proc/version

uname -a

lsb_release -a

# 无法执行命令安装
yum install -y redhat-lsb

更新YUM源:

yum update

安装:

yum  install docker -y

检查版本:

docker -v

安装完成后,使用下面的命令来启动 docker 服务,并将其设置为开机启动:

service docker start
chkconfig docker on

阿里云镜像加速

  1. 登陆阿里云, 找到"容器镜像服务"
  2. 找到"镜像加速器"
  3. 配置使用
  4. 重启Docker服务

docker run 的运行流程

底层原理

Docker是怎么工作的?

Docker 是一个 Client-Server 结构的系统, Docker的守护进程运行在主机上. 通过Socket从客户端访问!

DockerServer 接收到 Docker-Client 的指令, 就会执行这个命令!

Docker 为什么比 VM 快?

  1. Docker 有着比虚拟机更少的抽象层
  2. Docker 利用的是宿主机的内核, VM 需要的是Guest OS

所以说, 新建一个容器的时候, docker不需要像虚拟机一样重新家在一个操作系统内核, 避免隐刀. 虚拟机是加载Guest OS , 分钟级别的. 而Docker 是利用宿主机的操作系统, 省略了这个复杂的过程, 秒级!

Docker 的常用命令

帮助命令

docker verion				# 显示 docker 的版本信息
docker info					# 显示 docker 的系统信息, 包括镜像和容器的数量等
docker COMMAND --help		# 帮助命令

帮助文档的地址:Reference documentation | Docker Documentation

镜像命令

docker imagesdocker image | Docker Documentation

[root@Oskari docker]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/centos    7                   8652b9f0cb4c        8 months ago        204 MB

# 解释
REPOSITORY					# 镜像的仓库员
TAG							# 镜像的标签
IMAGE ID					# 镜像的id
CREATED						# 镜像的创建时间
SIZE						# 镜像的大小

# 可选项
-a 							# 列出所有镜像
-q							# 指向是镜像的id

docker search 搜索镜像docker search | Docker Documentation

[root@Oskari docker]# docker search mysql
INDEX       NAME                                        DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
docker.io   docker.io/mysql                             MySQL is a widely used, open-source relati...   11205     [OK]       
docker.io   docker.io/mariadb                           MariaDB Server is a high performing open s...   4259      [OK]       
docker.io   docker.io/mysql/mysql-server                Optimized MySQL Server Docker images. Crea...   833                  [OK]
docker.io   docker.io/percona                           Percona Server is a fork of the MySQL rela...   548       [OK]       
docker.io   docker.io/phpmyadmin                        phpMyAdmin - A web interface for MySQL and...   286       [OK] 

# 可选项
Name, shorthand	Default	Description
--filter , -f			Filter output based on conditions provided
--format				Pretty-print search using a Go template
--limit	25				Max number of search results
--no-trunc				Don't truncate output

# 通过收藏数量过滤
--filter=STARS=3000 	# 搜索STARS数量大于3000的

[root@Oskari docker]# docker search mysql -f=stars=3000
INDEX       NAME                DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
docker.io   docker.io/mysql     MySQL is a widely used, open-source relati...   11205     
docker.io   docker.io/mariadb   MariaDB Server is a high performing open s...   4259

docker pull 拉取镜像docker pull | Docker Documentation

# 下载镜像  docker pull IMAGENAME[:tag]
[root@Oskari docker]# docker pull mysql
Using default tag: latest			# 如果不写 tag ,  默认拉取最新版本
Trying to pull repository docker.io/library/mysql ... 
latest: Pulling from docker.io/library/mysql
33847f680f63: Pull complete 		# 分层下载, docker image 核心 [联合文件系统]
5cb67864e624: Pull complete 
1a2b594783f5: Pull complete 
b30e406dd925: Pull complete 
48901e306e4c: Pull complete 
603d2b7147fd: Pull complete 
802aa684c1c4: Pull complete 
715d3c143a06: Pull complete 
6978e1b7a511: Pull complete 
f0d78b0ac1be: Pull complete 
35a94d251ed1: Pull complete 
36f75719b1a9: Pull complete 
Digest: sha256:8b928a5117cf5c2238c7a09cd28c2e801ac98f91c3f8203a8938ae51f14700fd # 签名
Status: Downloaded newer image for docker.io/mysql:latest # 真实地址

# 下面两条命令是一样的涵义
docker pull mysql
docker pull docker.io/mysql:latest

# 指定版本下载
[root@Oskari docker]# docker pull mysql:5.7
Trying to pull repository docker.io/library/mysql ... 
5.7: Pulling from docker.io/library/mysql
33847f680f63: Already exists 			# 核心文件共用
5cb67864e624: Already exists 
1a2b594783f5: Already exists 
b30e406dd925: Already exists 
48901e306e4c: Already exists 
603d2b7147fd: Already exists 
802aa684c1c4: Already exists 
5b5a19178915: Pull complete 
f9ce7411c6e4: Pull complete 
f51f6977d9b2: Pull complete 
aeb6b16ce012: Pull complete 
Digest: sha256:be70d18aedc37927293e7947c8de41ae6490ecd4c79df1db40d1b5b5af7d9596
Status: Downloaded newer image for docker.io/mysql:5.7

[root@Oskari docker]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/mysql     5.7                 8cf625070931        12 days ago         448 MB
docker.io/mysql     latest              c60d96bd2b77        12 days ago         514 MB
docker.io/centos    7                   8652b9f0cb4c        8 months ago        204 MB

docker rmi 删除镜像

docker rmi IMAGENAME / IMAGE ID

# 批量删除
docker rmi -f $(docker images -aq)	# 查出所有镜像id, 递归删除

容器命令

下载一个CentOS镜像来测试学习

docker pull centos

新建容器并启动

docker run [ARGS] IMAGENAME 
# 参数说明
--name="NAME"				# 容器别称, 用来区分不同容器
-d							# 后来方式运行
-it							# 使用交互方式运行,进入容器查看内容
-p							# 指定容器的端口 -p 8080:8080
	-p ip:主机端口:容器端口
	-p 主机端口:容器端口(常用)
	-p 容器端口
# 测试 启动并进入容器
[root@Oskari docker]# docker run -it centos:7 /bin/bash
[root@1df2f1c76ad1 /]# ls # 查看容器内的centos, 基础版本, 很多命令都不是完善的.
# 从容器中退出主机
[root@1df2f1c76ad1 /]# exit 
[root@Oskari docker]

列出所有的运行的容器

# docker ps 			列出正在运行的容器
# docker ps -a 			列出当前正在运行的容器+历史运行过的容器
# docker ps -n=? 		显示最近创建的容器  ? number  指个数
# docker ps -q 			只显示容器的编号
[root@Oskari docker]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
[root@Oskari docker]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
1df2f1c76ad1        centos:7            "/bin/bash"         18 minutes ago      Exited (0) 8 seconds ago                       agitated_heyrovsky
[root@Oskari docker]#

退出容器

exit 			# 停止容器并退出
Ctrl+P+Q		# 保持容器运行并退出

删除容器

docker rm 容器id					 # 删除单个容器
docker rm 容器id 容器id	   			# 删除多个容器
docker rm -f $(docker ps -aq)		# 删除所有容器
docker ps -aq|xargs docker rm		# 删除所有容器

启动和停止容器的操作

docker start 容器id		# 启动容器
docker restart 容器id		# 重启容器
docker stop 容器id		# 停止当前正在运行的容器
docker kill 容器id		# 强制停止容器

常用其它命令

后台启动容器

# 命令 docker run -d IMAGENAME
[root@Oskari docker]# docker run -d centos
# 问题: docker ps 发现 centos 停止了
# 常见的坑: docker 容器使用后台运行, 就必须要有一个前台进程. docker发现没有应用, 就会自动停止

查看日志

# docker logs

[root@Oskari docker]# docker logs --help

Usage:	docker logs [OPTIONS] CONTAINER

Fetch the logs of a container

Options:
      --details        Show extra details provided to logs
  -f, --follow         Follow log output
      --help           Print usage
      --since string   Show logs since timestamp
      --tail string    Number of lines to show from the end of the logs (default "all")
  -t, --timestamps     Show timestamps
[root@Oskari docker]# docker logs -tf --tail 10 CONTAINER-ID # 查看某容器最后10条日志

查看容器中的进程信息

docker top CONTAINERID # 查看运行中的容器的进程

查看镜像的元数据

docker inspect containerid

进入当前正在运行的容器

# 容器通常设定为后台运行. 如果有进入容器的需要
[root@Oskari docker]# docker exec -it 25d00508c3f9 /bin/bash 	# 通过exec进入容器, 并创建一个 /bin/bash 进程
[root@Oskari docker]# docker attach 25d00508c3f9				# 通过attach进入容器, 进入正在运行的进程, 并不会创建进程

容器内拷贝文件到宿主机上

# docker cp 
# 进入容器, 创建要拷贝的文件
[root@Oskari docker]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
ef0508f169f9        centos:7            "/bin/bash"         2 minutes ago       Up 2 minutes                            tender_darwin
[root@Oskari docker]# docker attach ef0508f169f9
[root@ef0508f169f9 home]# ls
test.txt
[root@ef0508f169f9 home]# exit
# 退出容器, 进入宿主机, 可以不在意容器运行状态, 只要容器存在即可
[root@Oskari home]# pwd
/home
[root@Oskari home]# docker cp ef0508f169f9:/home/test.txt /home
[root@Oskari home]# ls
test.txt
[root@Oskari home]# cat test.txt 
test file from ef0508f169f9
[root@Oskari home]# 

# docker cp containerid:/path /path 
# 拷贝是一个手动过程, 未来我们可以使用 -v 卷的技术, 做到数据自动同步

作业练习

Docker 安装 Nginx

搜索镜像

[root@Oskari home]# docker search nginx

拉取镜像

[root@Oskari home]# docker pull nginx

后台方式启动Nginx镜像并重命名

[root@Oskari home]# docker run -d --name nginx01 -p 3344:80 nginx # 3344为宿主机端口,80为容器内部端口
0095b1e54ed30f6b71da17e6e975fe4af7982b58ec6b6b5c1efe19618a374f7d
[root@Oskari home]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
0095b1e54ed3        nginx               "/docker-entrypoin..."   4 seconds ago       Up 2 seconds        0.0.0.0:3344->80/tcp   nginx01

端口暴露概念

测试环境安装结果

[root@Oskari home]# curl localhost:3344
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@Oskari home]#

问题: 每次改动nginx配置文件, 都需要进入容器内部, 是分麻烦. 如果可以在容器外部提供一个映射路径, 达到在容器外部修改文件, 容器内部就可以自动修改? TIPS: -v 挂载卷

使用 Docker 安装一个 Tomcat

# 官方推荐命令 , 携带版本
docker run -it --rm tomcat:9.0 # 指定下载9.0版本
# 我们之前的启动都是后台, 停止容器之后, 容器还是可以查到.  --rm 在容器停止后会删除该镜像

启用一个新的tomcat容器, 别名 tomcat01, 宿主机使用3355映射容器的8080端口

docker run -d -p 3355:8080 --name tomcat01 tomcat

这里在宿主机中使用curl命令会发现 HTTP STAUS 404 , 原因: Tomcat 镜像为阉割版本

[root@Oskari home]# docker exec -it tomcat01 /bin/bash
root@8bbdd54e1ca5:/usr/local/tomcat# 
# 发现问题 1. linux 命令少了, ll 无法使用.  2. webapps 文件夹空.  3. 阿里云镜像的原因,默认是最小的镜像,剔除不必要的所有文件, 保证最小可运行环境
[root@Oskari home]# docker exec -it tomcat01 /bin/bash
root@8bbdd54e1ca5:/usr/local/tomcat# ls
BUILDING.txt  CONTRIBUTING.md  LICENSE	NOTICE	README.md  RELEASE-NOTES  RUNNING.txt  bin  conf  lib  logs  native-jni-lib  temp  webapps  webapps.dist  work
root@8bbdd54e1ca5:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@8bbdd54e1ca5:/usr/local/tomcat# ls webapps
ROOT  docs  examples  host-manager  manager
root@8bbdd54e1ca5:/usr/local/tomcat#

思考问题: 以后部署项目流程中, 每次都需要进入容器调整配置文件, 过于麻烦, 如何解决? TIPS: -v 挂载卷

部署 es + kibana

# es 暴露端口较多
# es 占用内存较多
# es 需要将数据放置到安全目录! 挂载

# 安装镜像,启动容器
[root@Oskari home]# docker run -d --name es01 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2 
# docker stats 查看 docker 内核运行状态
# 测试es是否安装成功
[root@Oskari home]# curl localhost:9200
{
  "name" : "0a772db1fcba",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "pFUYgLbEQWOUeVEdShsplQ",
  "version" : {
    "number" : "7.6.2",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
    "build_date" : "2020-03-26T06:34:37.794943Z",
    "build_snapshot" : false,
    "lucene_version" : "8.4.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}
[root@Oskari home]# 
# 增加 es 内存限制 -e 环境配置修改
[root@Oskari home]# docker run -d --name es02 -p 9200:9200 -p 9300:9300 -e ES_JAVA_OPTS="-Xms64m -Xmx512m" -e "discovery.type=single-node" elasticsearch:7.6.2

使用 kibana 链接 es

可视化管理

  • portainer (先用这个)

[root@Oskari home]# docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

  • Rancher (CI/CD再用)

什么是 portainer ?

Docker 图形化界面管理工具! 提供一个后台面板供我们操作!

[root@Oskari home]# docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

Docker 镜像讲解

Commit 镜像

docker commit 提交容器成为一个新的副本

# 命令和git原理类似
docker commit -m="描述信息" -a="作者" 容器id  目标镜像名:[TAG]

实战测试

# 启动一个默认的tomcat镜像, webapps里兵没有应用(镜像原因),  将webapps.list 下的所有文件移动至webapps文件夹下

# 将更改后的容器通过commit提交成为一个新的奖项.
[root@Oskari ~]# docker commit -a="oskari" -m="reset webapps files" 8bbdd54e1ca5 tomcat_normal:1.0
sha256:5e03b52c61624e583666cada38f58fb33e32b72ba17fe2e99b8bf1fdd6919b09
[root@Oskari ~]# docker images
REPOSITORY                      TAG                 IMAGE ID            CREATED             SIZE
tomcat_normal                   1.0                 5e03b52c6162        4 seconds ago       673 MB
docker.io/tomcat                9.0                 46cfbf1293b1        13 days ago         668 MB

如果想要保存当前容器的状态, 就可以通过 commit 来提交, 获取一个镜像. 就像VM的快照一样!

容器数据卷

什么是容器数据卷?

docker的理念

将应用和环境打包成一个镜像! 数据如果都存储在容器中, 如果容器被删除, 数据随之丢失. 故: 数据需要持久化. 通过容器之间数据共享技术, Docker容器中产生的数据同步到本地宿主机.

这就是卷技术! 目录的挂载, 将我们容器内的目录, 挂载到宿主机上!

总结: 容器的持久化和同步操作, 多个容器之间也是可以数据共享的!

使用数据卷

方式一: 直接使用命令 -v 进行数据地址挂载

docker run -it -v 宿主机目录:容器目录 IMAGENAME

测试一:

# 测试
[root@Oskari home]# docker run -it -v /home/test:/home centos:7 /bin/bash

# 查看卷是否挂载成功

[root@Oskari home]# docker inspect 3fe744aed21c

"Mounts": [ # 挂载
            {
                "Type": "bind",
                "Source": "/home/test", # 宿主机位置
                "Destination": "/home", # 容器内的位置
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
        
# 双向绑定
# 宿主机创建文件同步至容器
[root@Oskari test]# touch test.txt
[root@Oskari test]# docker attach 3fe744aed21c
[root@3fe744aed21c home]# ls
test.txt
[root@3fe744aed21c home]# 

# 容器内创建文件同步至宿主机
[root@3fe744aed21c home]# touch test_from_container.txt
# 退回至宿主机
[root@Oskari test]# ls
test_from_container.txt  test.txt

测试二:

# 在宿主机更改test.txt文件内容, 添加"This is update from Linux!"
# 在容器中查看文件内容, cat test.txt, 获取文字 "This is update from Linux!"

# 在容器冲更改test_from_container.txt 文件内容, 添加"This is update from Container!"
# 在宿主机中查看文件内容, cat test_from_container.txt, 获取文字 "This is update from Container!"

安装MySQL(持久化数据)

思考: MySQL的数据持久化的问题

以MySQL5.7为示例

启动MySQL5.7镜像, 创建容器, -p 端口映射, -v 挂载

# 启动镜像, 做配置文件以及数据挂载 
# 注意: 安装启动MySQL要配置ROOT密码!!!
# Offical: docker run --name some-mysql -e MY_ROOT_PASSWD=PASSWD -d mysql:tag
# -d 					后台运行
#-p 					端口映射
# -v 					数据卷挂载
# -e 					环境配置
# --name 		 容器名字
docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123123 --name mysql01 mysql:5.7

具名挂载和匿名挂载

# 匿名挂载
-P 大写的P, 映射随机端口
-v 容器内路径
docker run -d -P --name nginx02 -v /etc/nginx nginx

# 查看数据卷的相关帮助命令
docker volume --help

Options:
      --help   Print usage

Commands:
  create      Create a volume
  inspect     Display detailed information on one or more volumes
  ls          List volumes
  prune       Remove all unused volumes
  rm          Remove one or more volumes

# 查看所有数据卷信息
docker volume ls

DRIVER              VOLUME NAME
local               62c9d09e0c0693635857ea94246534747a7276950e1bd75f79260d25d2e9407e
local               dc0cc8aaee37ac6d0d9d68e4d7f08b26fe6867a3df396d29a62e119af7cfd121
# VOLUME NAME 当前显示为匿名数据卷, 在 -v 挂载的时候只写了容器内的路径,没有写宿主机的路径

# 具名挂载
# 通过 -v 卷名:容器内路径
docker run -d -P --name nginx03 -v juming-nginx:/etc/nginx nginx

所有Docker容器内的数据卷, 在没有指定目录的情况下都是在 /var/lib/docker/volumes/xxxx/_data 路径下.

我们通过具名挂载可以方便地找到我们需要查询的数据卷. 大多数情况都是在使用 具名挂载

# 如何确定是具名挂载还是匿名挂载, 亦或是指定路径挂载?
-v 容器内路径										# 匿名挂载
-v 数据卷名:/容器内路径					 # 具名挂载
-v /宿主机路径:/容器内路径			 # 指定路径挂载

拓展:

# 通过 -v 容器内路径: ro rw 改变读写权限
# ro readonly			只读
# rw readwrite		  读写
# 如果设置了容器权限, 容器对挂载出来的数据就有权限限定了. 
docker run -d -P --name nginx04 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx04 -v juming-nginx:/etc/nginx:rw nginx
# ro	只要看到ro就说明这个路径只能通过宿主机来操作, 容器内部是无法操作

初识Dockerfile

Dockerfile 就是用来构建 docker 镜像的构建文件的命令脚本

通过脚本生成镜像, 镜像是一层一层的. 脚本就是一个一个的命令, 每个命令都是一层.

创建 dockerfile1 文件

ROM centos

VOLUME ["volume01","volume02"]

CMD echo "-----VOLUME END-----"
CMD /bin/bash

执行构建镜像命令

docker build -f ./dockerfile1 -t oskari/centos:1.0 .

启动刚刚构建的镜像运行一个容器

这两个数据卷是在dockerfile1中挂载的(匿名挂载). 所以宿主机一定有一个与之同步的目录

查看数据卷挂载路径

# 进入容器,在挂载的数据卷 volume01 中创建测试文件container.txt文件
# 宿主机中查看容器源数据, 找到挂载信息
docker inspect c0fe3ce4ec96

        "Mounts": [
            {
                "Type": "volume",
                "Name": "a77fa64e6c71513d905f7307ad44df496dfcba948288113162dbf5ab036b317e",
                "Source": "/var/lib/docker/volumes/a77fa64e6c71513d905f7307ad44df496dfcba948288113162dbf5ab036b317e/_data",
                "Destination": "volume01",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            },
            {
                "Type": "volume",
                "Name": "d0c1bb2ca01b0e4c38d0cc3b0d3e632c8440fd98ea49811243a4283a86a77f55",
                "Source": "/var/lib/docker/volumes/d0c1bb2ca01b0e4c38d0cc3b0d3e632c8440fd98ea49811243a4283a86a77f55/_data",
                "Destination": "volume02",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

进入宿主机目录

cd /var/lib/docker/volumes/a77fa64e6c71513d905f7307ad44df496dfcba948288113162dbf5ab036b317e/_data

我们就能够看到刚刚创建的 container.txt 文件.( 当然, 你需要执行 ls 命令 )

数据卷容器

多个容器间同步

# 通过我们刚刚自己生成的镜像来启动一个容器
docker run -it -d --name docker01 oskari/centos:1.0  # 作为父容器

创建 docker02

# 创建docker02
docker run -it --name docker02 --volumes-from docker01 oskari/centos:1.0

进入 docker01 创建测试同步文档

[root@4cf79574d316 /]# docker attach docker01
[root@4cf79574d316 /]# cd volume01
[root@4cf79574d316 volume01]# ls
[root@4cf79574d316 volume01]# touch docker01.txt
[root@4cf79574d316 volume01]# ls
docker01.txt

进入 docker02 查看是否同步成功

[root@6a9129945bbe /]# docker attach docker02
[root@6a9129945bbe /]# cd volume01
[root@6a9129945bbe volume01]# ls
docker01.txt

--volume-from 相当于 继承

创建 docker03 (继承) 挂载于 docker02

[root@50cc8409521f /]# docker run -it --name docker03 --volumes-from docker02 oskari/centos:1.0 /bin/bash
[root@50cc8409521f /]# cd volume01
[root@50cc8409521f volume01]# ls
docker01.txt
[root@50cc8409521f volume01]# touch docker03.txt

分别进入 docker01 docker02 查看 volume01 目录下是否同步 docker03.txt 成功, 如果 docker03.txt 分别存在于 docker01 docker02volume01 目录内, 说明容器间的数据共享成功

只要通过 --volume-from 命令挂载, 那么容器间就可以做到数据共享了, 同时共享数据的容器间, 如果容器被删除, 数据依然存在于运行中的容器中.依然可以访问. 可以理解为容器之间, 数据共享等同于 容器间的双向拷贝!

多个MySQL实现数据共享(思路,代码非验证)

docker run -d -p 3310:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123123 --name mysql01 mysql:5.7
docker run -d -p 3311:3306 -e MYSQL_ROOT_PASSWORD=123123 --name mysql02 --volume-from mysql01 mysql:5.7

结论:

容器之间配置信息的传递, 数据卷容器的生命周期一直持续到没有容器使用为止.

但是如果持久化到了本地, 这个时候, 本地的数据是不会删除的.

Dockerfile

Dockerfile介绍

Dockerfile 是用来构成Docker镜像文件的命令参数脚本

构建步骤:

  1. 编写一个Dockerfile文件
  2. docker build 构建成为一个镜像
  3. docker run 运行镜像
  4. docker push 发布镜像 (DockerHUB 阿里云镜像仓库)

Dockerfile构建过程

基础知识:

  1. 每个保留关键字(指令)都必须是大写字母
  2. 指令是从上到下顺序执行的
  3. "#" 表示注释
  4. 没一个指令都会创建提交一个新的镜像层,并提交.

Dockerfile是面向开发的. 我们以后要发布的项目, 做镜像, 就需要编写dockerfile文件.

Docker 镜像逐渐成为企业交付的标准, 必须掌握!

Dockerfile 文件的构建, 定义了一切的步骤以及源代码.

Docker images 通过 Dockerfile 构建生成的镜像, 最终发布和运行的产品.

Docker containers 容器就是镜像运行起来提供服务.

Dockerfile 指令

FROM						# 基础镜像
MAINTAINER 			# 镜像作者   姓名+邮箱, 例如:   Oskari < oskari@bengder.cc >
RUN 						  # 镜像构建时需要运行的命令
ADD 						  # 添加内容, 例如 tomcat 压缩包
WORKDIR 			  # 镜像的工作目录
VOLUME 					# 挂载数据卷(目录)
EXPOSE 					 # 指定暴露端口
CMD							 # 指定容器启动的时候要运行的命令, 只有最后一个会生效, 可以被替代
ENTRYPOINT		  # 指定容器启动的时候要运行的命令, 可以追加命令
ONBUILD				   # 当构建一个被继承 Dockerfile , 这个时候就会运行 ONBUILD 指令, 触发指令
COPY						 # 类似 ADD 命令, 将文件拷贝到镜像中
ENV							   # 构建的时候设置环境变量

实战测试①

Docker Hub 中大多数镜像都是 FROM scratch 开始的. 然后配置需要的软件和配置来进行构建.

  1. 编写 Dockerfile 文件

FROM centos
MAINTAINER Oskari<oskari@bengder.cc>

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools
 
EXPOSE 80
 
CMD echo $MYPATH
CMD echo "IMAGE HAS BEEN BUILD SUCCESS!"

  1. 通过 Dockerfile 文件构建镜像

COMMAND: docker build -f dockerfile文件路径 -t 镜像名:版本号

docker build -f mydockerfile-centos -t mycentos .

运行镜像创建容器

docker run -it mycentos:1.0 /bin/bash
[root@8e1170f6d9f9 local]# ls
bin  etc  games  include  lib  lib64  libexec  sbin  share  src
[root@8e1170f6d9f9 local]# pwd
/usr/local
[root@8e1170f6d9f9 local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.18.0.3  netmask 255.255.0.0  broadcast 0.0.0.0
        inet6 fe80::42:acff:fe12:3  prefixlen 64  scopeid 0x20<link>
        ether 02:42:ac:12:00:03  txqueuelen 0  (Ethernet)
        RX packets 8  bytes 656 (656.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 8  bytes 656 (656.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
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        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

[root@8e1170f6d9f9 local]# vim test.txt
[root@8e1170f6d9f9 local]#

可以看到基于centos我们设置了进入容器后的工作目录, 安装了ifconfig vim 工具.

我们可以列出本地镜像的变更历史 docker history

docker history mycentos:1.0 # 这里要使用 镜像名:版本号   或者 IMAGE ID
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
cca92ffcc1b0        9 minutes ago       /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "/b...   0 B                 
3d83dcb4dbd9        9 minutes ago       /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "ec...   0 B                 
5c0d7d6368f8        9 minutes ago       /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "ec...   0 B                 
f7142fb9a548        9 minutes ago       /bin/sh -c #(nop)  EXPOSE 80/tcp                0 B                 
cb37ff0fda19        9 minutes ago       /bin/sh -c yum -y install net-tools             27.9 MB             
d125a97e66e0        9 minutes ago       /bin/sh -c yum -y install vim                   65.5 MB             
d4dbfdccb802        9 minutes ago       /bin/sh -c #(nop) WORKDIR /usr/local            0 B                 
96e44cb6ccfb        9 minutes ago       /bin/sh -c #(nop)  ENV MYPATH=/usr/local        0 B                 
d193dbeebed5        9 minutes ago       /bin/sh -c #(nop)  MAINTAINER Oskari<oskar...   0 B                 
300e315adb2f        8 months ago        /bin/sh -c #(nop)  CMD ["/bin/bash"]            0 B                 
<missing>           8 months ago        /bin/sh -c #(nop)  LABEL org.label-schema....   0 B                 
<missing>           8 months ago        /bin/sh -c #(nop) ADD file:bd7a2aed6ede423...   209 MB

实现测试②

  1. 准备镜像文件 tomcat 压缩包, JDK 的压缩包

cd /home/build/tomcat  		# 路径自由,随意些, 做足下面软件以及文件的准备
apache-tomcat-9.0.52-fulldocs.tar.gz  Dockerfile  jdk-16.0.2_linux-aarch64_bin.tar.gz  readme.txt

  1. 编写 Dockerfile ( 官方建议使用 Dockerfile , 在使用build 命令时, 无需添加 -f 参数)

FROM centos
MAINTAINER Oskari<oskari@bengder.cc>
COPY readme.txt /usr/local/readme.txt

# 在找包的时候请注意要与系统内核相对应
ADD jdk-8u301-linux-x64.tar.gz /usr/local
ADD apache-tomcat-9.0.52.tar.gz /usr/local

RUN yum -y install vim

ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk1.8.0_301
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.52
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.52
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

CMD /usr/local/apache-tomcat-9.0.52/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.52/logs/catalina.out

构建镜像

docker build -t tom .

启动镜像

# 挂载文件到宿主机并启动镜像
docker run -d -p 8090:8080 --name tomtest -v /home/build/tomcat/test:/usr/local/apache-tomcat-9.0.52/webapps/test -v /home/build/tomcat/tomcatlogs/:/usr/local/apache-tomcat-9.0.52/logs tom

查看挂载文件

访问容器

curl localhost:8090

可以看到正常返回的 html 代码. 亦可通过浏览器访问 IP:8090 查看容器状态是否正常运行

发布项目( 因为做了卷挂载, 所以在宿主机即可发布/编辑项目 )

/usr/build/tomcat/test/ 路径下创建 WEB-INF 文件夹, 创建配置文件 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/XMLScheme-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>

/usr/build/tomcat/test/ 路径下创建 index.jsp 文件

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
Hello World!<br/>
<%
out.println("你的 IP 地址 " + request.getRemoteAddr());
%>
</body>
</html>

访问 IP:8090/test/ , 会正常输出 Hello World! 等信息

发布自己的镜像

发布镜像到 Dockerhub

地址 https://hub.docker.com 注册账号

登陆账号

docker login -u YOUR_DOCKERHUB_ACCOUNT
Password: 	# 出现 Password 输入密码
Login Succeeded # 表示当前docker账户已登录

在服务器上进行镜像发布

docker push docker.io/zhangruoyucc/tom:1.0

Docker 网络

  • lo 本机回环地址
  • eth0 阿里云内网地址
  • docker0 docker0地址

三个网络

Docker 是如何处理容器网络访问的?

首先,我们启动一个tomcat, 尝试宿主机是否能够 ping 通容器

原理

  1. 每启动一个docker容器, docker便会给容器分配一个IP, 宿主机只要安装了docker, 就会有一个网卡 docker0
    桥接模式, 使用的技术是 veth-pair技术.
  2. 容器网卡使用veth-pair技术, 生成承兑的虚拟设备接口. 一端连着协议, 一端彼此项链. 正因为有这个特性, veth-pair充当了一个桥梁

结论: 容器是共用的一个路由器, docker0

所有的容器不指定网络的情况下, 都是 docker0 路由的, docker会给我们的容器分配一个默认的可用IP

Docker 使用的是Linux 的桥接模式. 宿主机中, docker0 是Docker容器的网桥

Docker 中的所有网络接口都是虚拟的. 因为虚拟的转发效率高. 如果删除容器, 对应网桥也会取消设置.

--link 解决容器之间通信

如何解决容器间的网络连通问题?

可以看到通过 --link 命令我们创建了 tom2容器 到 tom1容器的数据通道, 但是tom1容器 无法ping通 tom2容器

查看Docker 网络配置信息

docker network --help

[root@Oskari~] # docker exec -it tom2  cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.18.0.3	tom1 7cb82177b466
172.18.0.4	4d702d6e5629

在使用 --link 配置了 tom1容器, 即把tom1容器的ip, 别名, 配置到了 /etc/hosts 文件内.

现在已经不建议使用 --link 进行容器间的通信了. 因为 docker0并不支持容器名连接访问

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐