Docker入门

Docker入门

Docker概述

Docker 为什么会出现

在这里插入图片描述

在这里插入图片描述

Docker的历史

在这里插入图片描述

虚拟化技术和容器化技术对比

4.1. 虚拟化技术的缺点
  • 资源占用十分多
  • 冗余步骤多
  • 启动很慢

在这里插入图片描述

4.2. 容器化技术

在这里插入图片描述

  • 比较Docker和虚拟化技术的不同
    • 传统虚拟机, 虚拟出一条硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件
    • 容器内的应用直接运行在宿主机的内部,容器是没有自己的内核的,也没有虚拟硬件,所以轻便
    • 每个容器间是相互隔离的,每个容器内都有一个属于自己的文件系统,互不影响
    • 应用更快速的交互和部署
      • 传统:一堆帮助文档,安装程序
      • Docker: 打包镜像发布测试,一键运行
  • 更便捷的升级和扩缩容
  • 更简的系统运维
  • 更高效的计算资源利用

DevOps

在这里插入图片描述

Docker安装

Docker的基本组成

在这里插入图片描述

名词解释

  • 镜像(image)

    • Docker镜像就好比是一个模板,可以通过这个模板来创建容器服务,tomcat镜像 ===> run ===> tomcat01容器, 通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中的)
  • 容器(container)

    • Docker利用容器技术,独立运行一个或者一组应用, 通过镜像来创建的
    • 启动,停止,删除,基本命令!
    • 就目前可以把这个容器理解为一个简易的linux系统
  • 仓库(repository)

    • 存放镜像的地方
    • Docker Hub(默认是国外的)
    • 阿里云,都有容器服务(配置镜像加速!)

安装Docker

环境准备

  • 需要会一点点的Linux的基础
  • CentOS 7及以上
  • 我们使用Xshell]连接远程服务器进行操作

环境查看

[root@iZ2vc28obhvfham8wewhh0Z bin]# uname -r
4.18.0-193.14.2.el8_2.x86_64	# 内核版本,要求3.0以上
[root@iZ2vc28obhvfham8wewhh0Z bin]# cat /etc/os-release 
NAME="CentOS Linux"
VERSION="8 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="8"
PLATFORM_ID="platform:el8"
PRETTY_NAME="CentOS Linux 8 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:8"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"

CENTOS_MANTISBT_PROJECT="CentOS-8"
CENTOS_MANTISBT_PROJECT_VERSION="8"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="8"

阿里云镜像加速
  1. 登录阿里云服务器,找到容器镜像服务
  2. 设置Registry登录密码
  3. 找到镜像加速器
  4. 配置使用
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://pi9dpp60.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
正式安装(重要)

帮助文档: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(记住这个,不要忘记)
systemctl start docker

#6.使用docker version命令查看是否安装成功
docker version

#7.测试
docker run hello-world

img

#8.查看已经下载的镜像(从这里可以查看已有镜像的id)
[root@iZ2vc28obhvfham8wewhh0Z bin]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
hello-world   latest    d1165f221234   3 months ago   13.3kB

注意看这里的hello-world,就是我们刚刚去下载的镜像

4-卸载
#1.删除依赖
yum remove docker-ce docker-ce-cli containerd.io
#2.删除资源和容器
rm -rf /var/lib/docker
rm -rf /var/lib/containerd

#注:/var/lib/docker,是docker默认工作路径
#您必须手动删除任何已编辑的配置文件
阿里云镜像加速

登录阿里云找到容器镜像服务

image-20210610153101452

现在镜像加速器,选择centos,然后复制命令

image-20210610153330309

命令如下:

#1.新建目录
sudo mkdir -p /etc/docker
#2.在docker中的daemon.json里边配置了阿里云的地址
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://0k4g8w4k.mirror.aliyuncs.com"]
}
EOF
#3.重启镜像
sudo systemctl daemon-reload
#4.重启docker
sudo systemctl restart docker

底层原理

1-HelloWorld流程

docker run 流程分析图:

img

2-Docker的工作原理

  • Docker是一个Client-Server(cs)结构的系统,Docker的守护进程运行在主机上。通过Socket从客户端访问!
  • Docker-Server接收到Docker-Client的指令,就会执行这个命令!

image-20210610172024634

也就是许多的Docker-Client会连接后台守护进程,然后后台守护进程会去启动一个个的docker容器
在一个LInux服务器中,有许多的客户端,客户端会去连接到Docker的后台守护进程,通过守护进程去操作docker容器(可以把docker容器想成一个小的linux虚拟机,它也有许多的端口。所以说linux要去访问docker容器里边的东西,是需要再去做一个连通,之后讲解),docker容器会去获取资源。外边这个大的linux,和docker容器是相互隔离的。同时Docker在后台是一个特别大的服务

3-Docker快于VMware的原因

**docker有着比虚拟机更少的抽象层。**由于docker不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势
docker利用的是宿主机的内核,而不需要Guest OS
img

注意:看图中的VM中的App都是需要一个Guset OS的,而Docker中的App不需要

GuestOS: VM(虚拟机)里的的系统(OS)

HostOS:物理机里的系统(OS)
  • 当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。避免引导、加载操作系统内核返个比较费时费资源的过程,
  • 当新建一个虚拟机时,虚拟机软件需要加载GuestOS,这个新建过程是分钟级别的。
  • 而docker由于直接利用宿主机的操作系统,则省略了这个复杂的过程,因此新建一个docker容器只需要几秒钟。

4-Docker常用命令

1-帮助命令

docker version    #显示docker的版本信息。
docker info       #显示docker的系统信息,包括镜像和容器的数量,更详细
docker 命令 --help #帮助命令
#例如:方便查看语法格式,可选参数等,十分爽到
docker images --help
docker search --help
docker pull	--help

帮助文档的地址:https://docs.docker.com/reference/,查询相关命令

image-20210610184735587

2-镜像命令

docker images #查看所有本地主机上的镜像 可以使用docker image ls代替

docker search #搜索镜像

docker pull #下载镜像 docker image pull

docker rmi #删除镜像 docker image rm

2-1.docker images

此命令可以查看所有本地的主机上的镜像

[root@iZ2vc28obhvfham8wewhh0Z ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
hello-world   latest    d1165f221234   3 months ago   13.3kB

#1.解释
#REPOSITORY			# 镜像的仓库源
#TAG				# 镜像的标签(版本)		---lastest 表示最新版本
#IMAGE ID			# 镜像的id
#CREATED			# 镜像的创建时间
#SIZE				# 镜像的大小

#2.可选项(常用的2个)
Options:
  -a, --all         Show all images (default hides intermediate images) #列出所有镜像
  -q, --quiet       Only show numeric IDs # 只显示镜像的id
  
#3.示例
# docker images -a  #列出所有镜像详细信息
# docker images -aq #列出所有镜像的id

2-2.docker search

搜索镜像

比如搜索mysql

image-20210610213159374

[root@iZ2vc28obhvfham8wewhh0Z ~]# docker search mysql

#1.可选参数filter
Options:
  -f, --filter filter   Filter output based on conditions provided
      --format string   Pretty-print search using a Go template
      --limit int       Max number of search results (default 25)
      --no-trunc        Don't truncate output
# --filter=STARS=3000 #过滤,搜索出来的镜像收藏STARS数量大于3000的

#2.示例:
# docker search mysql --filter=STARS=3000
2-3.docker pull

下载镜像

# 下载镜像 docker pull 镜像名[:tag]
#上方的tag表示的是镜像的版本,如果不加就是默认下载的最新版
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker pull mysql
Using default tag: latest #下载的最新版
latest: Pulling from library/mysql
69692152171a: Pull complete  #分层下载: docker image 的核心 联合文件系统
1651b0be3df3: Pull complete 
951da7386bc8: Pull complete 
0f86c95aa242: Pull complete 
37ba2d8bd4fe: Pull complete 
6d278bb05e94: Pull complete 
497efbd93a3e: Pull complete 
f7fddf10c2c2: Pull complete 
16415d159dfb: Pull complete 
0e530ffc6b73: Pull complete 
b0a4a1a77178: Pull complete 
cd90f92aa9ef: Pull complete 
Digest: sha256:d50098d7fcb25b1fcb24e2d3247cae3fc55815d64fec640dc395840f8fa80969#签名,防伪标志
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest#真实地址

#知道真实地址:
#所以docker pull mysql等价于docker pull docker.io/library/mysql:latest

如要下载指定版本(tag的数据),在dockerhub上边一定要是可以查询到的

image-20210611122721147

[root@iZ2vc28obhvfham8wewhh0Z ~]# docker pull mysql:5.7
5.7: Pulling from library/mysql
#看到没,下方显示的是已存在,这就是分层下载的好处
#由于我们之前安装过mysql,现在安装mysql5.7版本就只下载与之前不一样的部分即可
#极大的节省内存空间
69692152171a: Already exists 
1651b0be3df3: Already exists 
951da7386bc8: Already exists 
0f86c95aa242: Already exists 
37ba2d8bd4fe: Already exists 
6d278bb05e94: Already exists 
497efbd93a3e: Already exists 
a023ae82eef5: Pull complete 
e76c35f20ee7: Pull complete 
e887524d2ef9: Pull complete 
ccb65627e1c3: Pull complete 
Digest: sha256:a682e3c78fc5bd941e9db080b4796c75f69a28a8cad65677c23f7a9f18ba21fa
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7

image-20210611123249262

2-4.docker rmi

删除镜像

#1.首先我们查询出docker中的镜像
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
mysql         5.7       2c9028880e58   4 weeks ago    447MB
mysql         latest    c0cdc95609f1   4 weeks ago    556MB
hello-world   latest    d1165f221234   3 months ago   13.3kB

#2.删除镜像,可以通过REPOSITORY或者IMAGE ID来删除
docker rmi -f 镜像id #删除指定id的镜像
#咱们尝试通过mysql5.7的image id来删除它
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker rmi -f 2c9028880e58
Untagged: mysql:5.7
Untagged: mysql@sha256:a682e3c78fc5bd941e9db080b4796c75f69a28a8cad65677c23f7a9f18ba21fa
Deleted: sha256:2c9028880e5814e8923c278d7e2059f9066d56608a21cd3f83a01e3337bacd68
Deleted: sha256:c49c5c776f1bc87cdfff451ef39ce16a1ef45829e10203f4d9a153a6889ec15e
Deleted: sha256:8345316eca77700e62470611446529113579712a787d356e5c8656a41c244aee
Deleted: sha256:8ae51b87111404bd3e3bde4115ea2fe3fd2bb2cf67158460423c361a24df156b
Deleted: sha256:9d5afda6f6dcf8dd59aef5c02099f1d3b3b0c9ae4f2bb7a61627613e8cdfe562

#3.了解删除全部镜像的命令
docker rmi -f $(docker images -aq) #删除全部的镜像
#通过docker images -aq查询出来的所有镜像进行删除

3-容器命令

说明:我们有了镜像才可以创建容器,Linux,下载centos镜像来学习

docker pull centos

主要命令一览:

docker run 镜像id #新建容器并启动

docker ps 列出所有运行的容器 docker container list

docker rm 容器id #删除指定容器

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

3-1.新建容器并启动
docker run [可选参数] image | docker container run [可选参数] image 
#参书说明
--name="Name"		#容器名字,比如:tomcat01 tomcat02 用来区分容器
-d					#后台方式运行
-it 				#使用交互方式运行,进入容器查看内容
-p					#指定容器的端口,-p 8080(宿主机):8080(容器)
#-p,这个是小写p。主要用法有几种:
	#1.-p	主机端口:容器端口(常用)
	#2.-p	容器端口
	#3.容器端口
	#4.-p	ip:主机端口:容器端口
-P					#随机指定端口

测试:

#一:测试:
#1.使用命令运行并进入容器,通过的是bash命令
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker run -it centos bin/bash
#2.注意看上方的主机名变为了7000b6708eea,其实这个就是centos的image id
[root@7000b6708eea /]# 
#3.咱们尝试使用ls命令查看容器内部的centos,结果发现和主机的目录是相差无几
[root@7000b6708eea /]# ls
bin  etc   lib	  lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr
#4.退出容器到主机
[root@7000b6708eea /]# exit
exit
[root@iZ2vc28obhvfham8wewhh0Z ~]# 

3-2.列出所有运行的容器

主要命令介绍:

docker ps 命令  		#列出当前正在运行的容器
  -a, --all     	 #列出当前正在运行的容器 + 历史运行过的容器
  -n=?, --last int   #列出最近创建的?个容器 ?为1则只列出最近创建的一个容器,为2则列出2个
  -q, --quiet        #只列出容器的编号
3-3.退出容器
exit 		#容器直接退出
ctrl +P +Q  #容器不停止退出 	---注意:这个很有用的操作
3-4.删除容器
docker rm 容器id   				#删除指定的容器,不能删除正在运行的容器,如果要强制删除 rm -rf
docker rm -f $(docker ps -aq)  	 #删除所有的容器,又是参数传递方式,搜出来的结果删
docker ps -a -q|xargs docker rm  #删除所有的容器
#xargs命令也是一个个的删除,这里的|是管道符,学linux的时候提过
3-5.启动和停止容器的操作
docker start 容器id	#启动容器
docker restart 容器id	#重启容器
docker stop 容器id	#停止当前正在运行的容器
docker kill 容器id	#强制停止当前容器

4-常用其他命令

4-1.后台启动容器
# 命令 docker run -d 镜像名
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker run -it centos bin/bash

#测试:
#1.后台运行centos
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker run -d centos
dfec0e9a77be8a277779477dc0d5d74b2be42e182cd4cd62efa92547f6833b3a
#2.查看运行中的容器,发现没有
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
# 问题docker ps. 发现centos 停止了
# 常见的坑,docker容器使用后台运行,就必须要有要一个前台进程,docker发现没有应用,就会自动停止。
#Docker容器后台运行,必须有一个前台进程。容器运行的命令如果不是那些一直挂起的命令(比如运行ping,sleep),就是会自动退出的。
#(这样想docker发现启动了也提供不了服务,没有东西需要它就自己关闭了,即是快速开,快速关)
# 比如nginx,容器启动后,发现自己没有提供服务,就会立刻停止自杀,就是没有程序了

4-2.查看日志
#1.查看
docker logs --help
#可选项,非常多啊
Options:
      --details        Show extra details provided to logs 
*  -f, --follow         Follow log output
      --since string   Show logs since timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)
*      --tail string    Number of lines to show from the end of the logs (default "all")
*  -t, --timestamps     Show timestamps
      --until string   Show logs before a timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)
➜  ~ docker run -d centos /bin/sh -c "while true;do echo 6666;sleep 1;done" #模拟日志 

#2.显示日志
-tf		#显示日志信息(一直更新)
--tail number #需要显示日志条数
docker logs -t --tail n 容器id #查看n行日志
docker logs -tf 容器id #跟着日志

4-3.查看容器中进程信息ps
# 命令 docker top 容器id
4-4.查看镜像的元数据
# 命令
docker inspect 容器id

#查看元数据
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker inspect 0694e2e1032c
[
    {
        "Id": "0694e2e1032cc54a101e50adbab5f72a447525f5604b0201ac933e3800c2928d",
        "Created": "2021-06-11T09:12:42.494496381Z",
        "Path": "bin/bash",
        "Args": [],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 2225148,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2021-06-11T09:12:43.695461095Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:300e315adb2f96afe5f0b2780b87f28ae95231fe3bdd1e16b9ba606307728f55",
        "ResolvConfPath": "/var/lib/docker/containers/0694e2e1032cc54a101e50adbab5f72a447525f5604b0201ac933e3800c2928d/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/0694e2e1032cc54a101e50adbab5f72a447525f5604b0201ac933e3800c2928d/hostname",
        "HostsPath": "/var/lib/docker/containers/0694e2e1032cc54a101e50adbab5f72a447525f5604b0201ac933e3800c2928d/hosts",
        "LogPath": "/var/lib/docker/containers/0694e2e1032cc54a101e50adbab5f72a447525f5604b0201ac933e3800c2928d/0694e2e1032cc54a101e50adbab5f72a447525f5604b0201ac933e3800c2928d-json.log",
        "Name": "/crazy_tereshkova",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "CgroupnsMode": "host",
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "ConsoleSize": [
                0,
                0
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "KernelMemory": 0,
            "KernelMemoryTCP": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/09513686c655ebe17e0790eb3d32108bd6b152427072c49bb9a3d561d76f9d54-init/diff:/var/lib/docker/overlay2/ad0b9110de723291fa2fb4bc89a3ab11dac79ed0f77dad963ac3e7d7ef35d837/diff",
                "MergedDir": "/var/lib/docker/overlay2/09513686c655ebe17e0790eb3d32108bd6b152427072c49bb9a3d561d76f9d54/merged",
                "UpperDir": "/var/lib/docker/overlay2/09513686c655ebe17e0790eb3d32108bd6b152427072c49bb9a3d561d76f9d54/diff",
                "WorkDir": "/var/lib/docker/overlay2/09513686c655ebe17e0790eb3d32108bd6b152427072c49bb9a3d561d76f9d54/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [],
        "Config": {
            "Hostname": "0694e2e1032c",
            "Domainname": "",
            "User": "",
            "AttachStdin": true,
            "AttachStdout": true,
            "AttachStderr": true,
            "Tty": true,
            "OpenStdin": true,
            "StdinOnce": true,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "bin/bash"
            ],
            "Image": "centos",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "org.label-schema.build-date": "20201204",
                "org.label-schema.license": "GPLv2",
                "org.label-schema.name": "CentOS Base Image",
                "org.label-schema.schema-version": "1.0",
                "org.label-schema.vendor": "CentOS"
            }
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "ba1eb305552ee290cd4ecc492737310fca79864556f11e03c60e506652238a8e",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {},
            "SandboxKey": "/var/run/docker/netns/ba1eb305552e",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "8a73cec4bec6a1d7e7e29754cca64cd046bb24f1f72243f97da44f26d90683da",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:02",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "0324214c08ea6d191e80bea1165d5da073963b214d35d17423b9baedab404824",
                    "EndpointID": "8a73cec4bec6a1d7e7e29754cca64cd046bb24f1f72243f97da44f26d90683da",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02",
                    "DriverOpts": null
                }
            }
        }
    }
]
4-5.进入当前正在运行的容器(重要)
#我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置
#====================方式一====================
#1.命令
docker exec -it 容器id bashshell

#2.测试
#进入容器
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker exec -it 0694e2e1032c bin/bash
#进入容器之后我们想干嘛干嘛,比如使用ls命令查看东西之类
[root@0694e2e1032c /]# ls
bin  etc   lib	  lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr

#====================方式二====================
#1.命令
docker attach 容器id
#2.测试
docker attach 0694e2e1032c
正在执行当前的代码...
#方式一和方式二的区别
#docker exec #进入当前容器后开启一个新的终端,可以在里面操作。(常用)
#docker attach # 进入容器正在执行的终端,不会启动新的进程

4-6从容器内拷贝到主机上
#1.命令
docker cp 容器id:容器内路径(文件名)  主机目的路径
#2.测试
docker cp 0694e2e1032c:/hello.java /home 
#将容器内部的/hello.java移动到主机的/home目录下,即使容器关闭了,也可以拷贝出来

#拷贝是一个手动过程,未来我们使用-v卷的技术,可以实现自动同步

5-小结

image-20210612010113181

图中的Container以及images的些许命令我们已经学过了,注意看图中的命令吧好多过了一遍了

命令大全

attach      Attach local standard input, output, and error streams to a running container
#当前shell下 attach连接指定运行的镜像
build       Build an image from a Dockerfile # 通过Dockerfile定制镜像
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 
#查看docker容器的变化
events      Get real time events from the server # 从服务获取容器实时时间
exec        Run a command in a running container # 在运行中的容器上运行命令
export      Export a container's filesystem as a tar archive 
#导出容器文件系统作为一个tar归档文件[对应import]
history     Show the history of an image # 展示一个镜像形成历史
images      List images #列出系统当前的镜像
import      Import the contents from a tarball to create a filesystem image #从tar包中导入内容创建一个文件系统镜像
info        Display system-wide information # 显示全系统信息
inspect     Return low-level information on Docker objects #查看容器详细信息
kill        Kill one or more running containers # kill指定docker容器
load        Load an image from a tar archive or STDIN #从一个tar包或标准输入中加载一个镜像[对应save]
login       Log in to a Docker registry #
logout      Log out from a Docker registry
logs        Fetch the logs of a container
pause       Pause all processes within one or more containers
port        List port mappings or a specific mapping for the container
ps          List containers
pull        Pull an image or a repository from a registry
push        Push an image or a repository to a registry
rename      Rename a container
restart     Restart one or more containers
rm          Remove one or more containers
rmi         Remove one or more images
run         Run a command in a new container
save        Save one or more images to a tar archive (streamed to STDOUT by default)
search      Search the Docker Hub for images
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
tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
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
version     Show the Docker version information
wait        Block until one or more containers stop, then print their exit codes
6-作业练习
6-1.安装Nginx
1.安装过程
#1. 搜索镜像 search 建议大家去docker搜索,可以看到帮助文档
docker search nginx

#2. 拉取下载镜像 pull
docker pull nginx

#3. 查看是否下载成功镜像
docker images

#4. 运行nginx
# -d 后台运行
# --name 给容器命名
# -p 宿主机端口:容器内部端口
docker run -d --name nginx01 -p 3344:80 nginx
#也就是说我们可以通过公网的3344,访问到docker的80

#5. 查看正在启动的镜像
docker ps

#6. 测试
#curl命令,利用URL规则在命令行下工作的文件传输工具
#如:curl http://www.linux.com,执行后,www.linux.com 的html就会显示在屏幕上了
#下方访问的是3344端口,显示的是nginx的网页代码,测试完毕

[root@iZ2vc28obhvfham8wewhh0Z ~]# 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>

#7. 进入容器,查看信息
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker exec -it nginx01 /bin/bash
root@8d0bb7bed5f2:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@8d0bb7bed5f2:/# cd /etc/nginx   
root@8d0bb7bed5f2:/etc/nginx# ls    
conf.d	fastcgi_params	mime.types  modules  nginx.conf  scgi_params  uwsgi_params
#注意nginx.conf,就是配置文件

2.宿主机端口容器内部端口 以及端口暴露:

image-20210612011832739

  • 外网:即是linux外部的网络
  • 阿里云的安全组:阿里云的端口要从这里开放,比如开放了3344。
  • 防火墙3344:是linux内部的防火墙开启了3344端口
  • -p 3344:80:通过这个操作,暴露端口,我们宿主机的3344就能访问到容器的80端口

现在有一个大大的linux,linux中有个防火墙开启了3344端口,docker服务里边有很多个容器,容器类似于一个独立的小的linux环境,所以有一个小的防火墙,开启了80端口。咱们是外网,先访问阿里云安全组的3344端口,看看端口有没有问题,没有就进入到linux的3344端口,然后通过-p 3344:80使得linux的3344端口可以访问到容器内部的80端口,最终到达Nginx。

3.测试一下3344端口:

image-20210612013521416

  1. **问题:**我们每次改动nginx配置文件,都需要进入容器内部?十分麻烦,我要是可以在容器外部提供一个映射路径,达到在容器外部修改文件,容器内部就可以自动修改?-v 数据卷 技术!(后面会讲到就是容器的文件目录挂载到宿主机实现数据的保存)
6-2.安装tomcat
# 下载 tomcat9.0
# 命令:docker run -it --rm 镜像名,注意看命令中带有了--rm,表示用完就删除
# 之前的启动都是后台,停止了容器,容器还是可以查到还存在,一般是用来测试,用完就删除

#1. 下载tomcat最新版
docker pull tomcat

#2. 查看下载的镜像
docker images

#3. 以后台方式,暴露端口方式,启动运行
docker run -d -p 3355:8080 --name tomcat02 tomcat

#4. 测试访问有没有问题
curl localhost:3355 #测试没问题,但是外网访问的话是404,这个问题需要下面的第七步解决

#5. 根据容器id进入tomcat容器
docker exec -it 1c9d3fc1dac5 /bin/bash

#6. 其实这个tomcat是阉割版
# 发现问题:1、linux命令少了。 2.webapps目录为空 
# 原因:阿里云镜像的原因,阿里云默认是最小的镜像,所以不必要的都剔除掉
# 保证最小可运行的环境!
# 解决方案:
# 将webapps.dist下的文件都拷贝到webapps下即可

#7. 将webapps.dist下的文件都拷贝到webapps下
#进入容器
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker exec -it 1c9d3fc1dac5 /bin/bash
#查看文件目录,含有webapps.dist
root@1c9d3fc1dac5:/usr/local/tomcat# ls
BUILDING.txt	 LICENSE  README.md	 RUNNING.txt  conf  logs	    temp     webapps.dist
CONTRIBUTING.md  NOTICE   RELEASE-NOTES  bin	      lib   native-jni-lib  webapps  work
#将webapps.dist所有东西复制到webapps文件夹中
root@1c9d3fc1dac5:/usr/local/tomcat# cp -r webapps.dist/* webapps

问题:我们以后要部署项目,如果每次都要进入容器是不是十分麻烦?要是可以在容器外部提供一个映射路径,比如webapps,我们在外部放置项目,就自动同步内部就好了!

6-3.部署elasticsearch+kibana
  • 首先es有诸多不足,咱们要想办法解决:
    1. es 暴露的端口很多!
    2. es 十分耗内存
    3. es 的数据一般需要放置到安全目录!挂载
# 下方的命令是dockerhub上边的官方启动命令
#1. --net somenetwork,这个是网络配置,之后再讲
#2. -p 9200:9200 -p 9300:9300,暴露了9200和9300端口
#3. "discovery.type=single-node",这个是一个集群,表示单个节点
#4. :tag,最新的版本·
docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:tag

开始操作:

#1. 使用简化版命令启动
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2

#启动了很可能会卡,我们查看一下CPU的状态
docker stats 
#也可以停止一些
docker stop 镜像id


#2. 测试一下es是否成功启动
[root@iZ2vc28obhvfham8wewhh0Z ~]# curl localhost:9200
{
  "name" : "9e8f30f010b9",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "N_kPtsMqT4u0eYSeCtczJg",
  "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"
}

#3. 测试成功就关掉elasticSearch,防止耗内存,正常来说要关半天,太卡了。后悔启动了草
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker stop 0694e2e1032c
0694e2e1032c

image-20210615205851623

#测试成功就关掉elasticSearch,可以看出elasticsearch非常占内存,我们可以修改配置文件,进行限制内存使用#修改配置文件 -e 环境配置修改
# 在我们之前的启动命令中加入:-e ES_JAVA_OPTS="-Xms64m -Xmx512m",限定内存在64mb-512mb之间
docker run -d --name elasticsearch2 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2

#再次查看docker stats,发现变小了,非常爽到

image-20210615213705148

使用kiba6na连接es (elasticSearch)?思考网络如何才能连接

image-20210615214159685
现在elasticsearch容器和kibana容器都是相互隔离的,elasticsearch和kibana都有各自的内部地址。我们可以通过Linux的内网的ip作为一个中间商就可以实现elasticsearch到kibana访问,但是会涉及到Docker的网络相关的知识,在之后讲解。(请记住veth-pair)

五、可视化面板安装

  • portainer(先用这个,不是最佳选择)
# -v,挂载
# privileged,授权
docker run -d -p 8080:9000 \
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

  • Rancher(CI/CD再用)

1-什么是portainer?

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

  1. 使用命令启动portainer
# -v,挂载
# privileged,授权
docker run -d -p 8080:9000 \
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

​ 2.外网访问8080端口(记得阿里云安全组打开8080端口),然后设置密码

image-20210615221515623

​ 3.选择本地

image-20210615221753488

​ 4.然后进入管理页面,可以查看相关信息(使用较少)

image-20210615221929541

六、镜像原理

1-镜像是什么

  • 镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时库、环境变量和配置文件。
  • 所有应用,直接打包docker镜像,就可以直接跑起来

2-如何得到镜像

  • 从远程仓库下载
  • 别人拷贝给你
  • 自己制作一个镜像 DockerFile

3-Docker镜像加载原理

3-1.UnionFs (联合文件系统)

首先明确这个概念,然后我们下载的时候看到的一层层的就是这个

  • UnionFs(联合文件系统):Union文件系统(UnionFs)是一种分层、轻量级并且高性能的文件系统,他支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下( unite several directories into a single virtual filesystem)。

  • Union文件系统是 Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像

  • 特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

3-2.Docker镜像加载原理

docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。接下来明确两个名词概念:

  1. bootfs(boot file system):主要包含 bootloader(加载器)和 Kernel(内核),bootloader主要是引导加载kernel,Linux刚启动时会加bootfs文件系统,在 Docker镜像的最底层是 boots。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由 bootfs转交给内核,此时系统也会卸载bootfs。(说白了就是电脑黑屏—>加载—>开机,三个阶段中的加载部分,用完就不需要的就卸载掉)
  2. rootfs(root file system):在bootfs之上。包含的就是典型 Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。 rootfs就是各种不同的操作系统发行版,比如 Ubuntu,Centos等等。

接下来我们看个图:

image-20210624152552461

  • 第一阶段:只有bootfs和rootfs
  • 第二阶段:bootfs和rootfs部分加上了images
  • 第三阶段:bootfs和rootfs部分加上了images,再加上images…无限加层,千层饼

平时我们安装进虚拟机的Centos都是好几个G,为什么Docker这里只有200M?

image-20210624155543229

对于一个精简的OS(操作系统),rootfs可以很小,只需要包合最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel(主机的内核),自己只需要提供rootfs就可以了。由此可见对于不同的Linux发行版, boots基本是一致的, rootfs会有差別,因此不同的发行版可以公用bootfs。所以说虚拟机是分钟级别,容器是秒级!

4-分层理解

4-1.查看分层
  • 我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层层的在下载

image-20210624172051526

  • 思考:为什么Docker镜像要采用这种分层的结构呢?

最大的好处,我觉得莫过于资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。

  • 咱们使用docker image inspect tomcat,查看一下分层,主要看一下layers
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker image inspect tomcat
[...
        "RootFS": {
            "Type": "layers",
            "Layers": [#以下的就相当于是一个个的记录,有10条,对应上方的10条pull complete
                "sha256:688e187d6c79c46e8261890f0010fd5d178b8faa178959b0b46b2635aa1eeff3",
                "sha256:00bcea93703b384ab61d2344d6e721c75b0e47198b7912136a86759d8d885711",
                "sha256:ccb9b68523fdb47816f2a15d7590d06ff3d897dfdb3e0733e9c06a2bb79ebfc7",
                "sha256:685934357c8993799eda4a6d71c2bb2d2c54b1138d6e037f675eeeeffc719f2d",
                "sha256:3fc095fab4a2bec54616a8f5c20c43a9fe197ad06c2cf81385578dfe79aed238",
                "sha256:6f770cdc9ebf757c2f2f6395c3cdb6f4298f5860727de340890a9a855e168e6e",
                "sha256:15786a1cf1cbf50fea509d04227d327416c7c0c8b42b9488b56416095ba2f434",
                "sha256:8f8b5acac684a1fb664c6301413fd28d50ac0f28c7fb8a01c24eee6cd4799739",
                "sha256:3307ffa538c1bbc8f7d1cf8a5f0fbcd08634a7001dbf92c619e7720fb334df70",
                "sha256:daf63ef0ddbb5fd50852b4bfc2f5f9fd0be4923819608d4f6051fc23809985c9"
            ]
        }...
]
4-2.探究理解
  1. 所有的 Docker镜像都起始于一个基础镜像层,当进行修改或培加新的内容时,就会在当前镜像层之上,创建新的镜像层

  2. 举一个简单的例子,假如基于 Ubuntu Linux16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加 Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创健第三个镜像层该像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)

  3. 在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点

image-20210624172651059

  1. 在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个镜像层包含3个文件,而将这两个层进行打包之后,镜像包含了来自两个镜像层的6个文件。

image-20210624172941343

  1. 上图中的镜像层跟之前图中的略有区別,主要目的是便于展示文件

  2. 下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版

image-20210624173559112

  1. 这种情況下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中
    • Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统
    • Linux上可用的存储引撃有AUFS、 Overlay2、 Device Mapper、Btrfs以及ZFS。顾名思义,每种存储引擎都基于 Linux中对应的文件系统或者块设备技术,井且每种存储引擎都有其独有的性能特点。
    • Docker在 Windows上仅支持 windowsfilter 一种存储引擎,该引擎基于NTFS文件系统之上实现了分层和CoW 。
  2. 下图展示了与系统显示相同的三层镜像。所有镜像层堆并合井,对外提供统一的视图。

image-20210624173803228

4-3.特点

Docker 镜像都是只读的,当容器启动时,一个新的可写层加载到镜像的顶部!这一层就是我们通常说的容器层,容器之下的都叫镜像层(无法改变的,从远程pull的)!

相当于咱们pull的tomcat是只读的,然后我们要进行操作的话,也就是我们使用run命令去启动的时候,相当于新加了一层,新的这一层来进行操作。

image-20210624180115303

5-commit镜像(提交自己的镜像)

5-1.语法
docker commit 提交容器成为一个新的副本

# 命令和git原理类似
docker commit -m="描述信息" -a="作者名字" 容器id 目标镜像名:[版本TAG]
5-2.测试
#1. 启动一个默认的tomcat
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker run -it -p 8080:8080 tomcat

#2. 发现这个默认的tomcat 是没有webapps应用,官方的镜像默认webapps下面是没有文件的!
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker exec -it 079f8174730f /bin/bash

#3. 将webapps.dist里的所有东西拷贝文件进webapps,并查看
root@079f8174730f:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@079f8174730f:/usr/local/tomcat# cd webapps
root@079f8174730f:/usr/local/tomcat/webapps# ls
ROOT  docs  examples  host-manager  manager

#4. 操作过的容器通过commit调教为一个镜像!我们以后就使用我们修改过的镜像即可,而不需要每次都重新拷贝webapps.dist下的文件到webapps了,这就是我们自己的一个修改的镜像。
docker commit -m="描述信息" -a="作者" 容器id 目标镜像名:[TAG]
docker commit -a="peng" -m="add webapps app" 容器id tomcat02:1.0

[root@iZ2vc28obhvfham8wewhh0Z ~]# docker commit -a="haha" -m="add webapps app" 079f8174730f tomcat02:1.0
sha256:b0a602f7e277d044ec71dbc36450609a0652f316e06c51fdcc82338de792793e
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED              SIZE
#看下方这个tomcat02.1.0就是我们创建的镜像,发布之后再说
tomcat02.1.0          1    		b0a602f7e277   About a minute ago   672MB
tomcat                9         6654503f1940   7 hours ago          667MB
nginx                 latest    d1a364dc548d   4 weeks ago          133MB
tomcat                latest    c43a65faae57   5 weeks ago          667MB
mysql                 latest    c0cdc95609f1   6 weeks ago          556MB
portainer/portainer   latest    580c0e4e98b0   3 months ago         79.1MB
hello-world           latest    d1165f221234   3 months ago         13.3kB
centos                latest    300e315adb2f   6 months ago         209MB
elasticsearch         7.6.2     f29a1ee41030   15 months ago        791MB

如果你想要保存当前容器的状态,就可以通过commit来提交,获得一个镜像,就好比我们我们使用虚拟机的快照。对应tag,因为tag可以自定义,以后我们可以自定义1.0版本或者2.0版本。

七、容器数据卷

1-什么是容器数据卷

docker的理念是将应用和环境打包成一个镜像!

如果数据都在容器中,那么我们容器删除,数据就会丢失!所以我们就有需求:数据可以持久化

比如:安装了MySQL,容器删除了,相当于删库跑路!所以我们就有需求:MySQL数据可以存储在本地!

所以我们需要容器之间可以有一个数据共享的技术!Docker容器中产生的数据,同步到本地!

这就是卷技术!说白了就是目录的挂载,将我们容器内的目录,挂载到Linux上面!

总结一句话:容器的持久化和同步操作!容器间也是可以数据共享的!
image-20210625154806450

将mysql容器内部的文件系统映射(挂载)到linux上边,实现数据的持久化和同步

2-使用数据卷

2-1.方式一 :直接使用命令挂载 -v
#1. 语法:主要是这个-v
docker run -it -v 主机目录:容器内目录  -p 主机端口:容器内端口

#2. run一个centos容器,并使用目录挂载
# /home/ceshi:主机home目录下的ceshi文件夹  映射:centos容器中的/home
# 将容器里边的home目录挂载到linux的home下边的ceshi目录
docker run -it -v /home/ceshi:/home centos /bin/bash

#3.  docker inspect 容器id 查看是否挂载成功
[root@iZ2vc28obhvfham8wewhh0Z /]# docker inspect 54db68df3d7f
#具体看下图的Mounts部分,以后两个地址的内的数据可以相互同步的

image-20210625190022883

#4. 测试文件是否相互同步,看图

image-20210625191121195

#5. 再来测试!
1、停止容器

2、宿主机修改文件(修改之前的test.java文件,向内部添加“hello,linux update”)

3、再次启动容器

4、容器内的数据依旧是同步的

image-20210625191647599

好处:我们以后修改只需要在本地修改即可,容器内会自动同步

2-2.实战:安装MySQL

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

#1. 获取mysql镜像
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker pull mysql:5.7

#2. 运行容器的时候需要做数据挂载,此处我们挂载了配置文件以及数据目录(有两个哦),同时咱们也配置了mysql的密码
-d 后台运行
-p 端口映射
-v 卷挂载
-e 环境配置
-- name 容器名字
[root@iZ2vc28obhvfham8wewhh0Z ~]# 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=123456 --name mysql01 mysql:5.7

#3. 启动成功之后,我们可以在本地去连接上服务器的mysql,如下图所示
#咱们走的是3310端口,3310端口映射了容器的3306端口,所以说我们本质还是访问到的容器
#4. 咱们测试一下本地创建数据库,远程能否生成
#4-1. 使用navicat创建数据库hahahaha
#4-2. 使用xshell进入/home/mysql/data目录查看

image-20210625195447101

总结:通过这样的操作就可以一定程度上保证数据不会丢失,同时以后启动容器也可以使用此数据

2-3.扩展:具名和匿名挂载

理解概念:

#1. 匿名挂载
-v 容器内路径!,这里我们没有写主机的路径,那么它就会自动的生成一个目录
#1-1. 使用命令匿名挂载
docker run -d -P --name nginx01 -v /etc/nginx nginx

#1-1. 查看所有volume(卷)的情况  
[root@iZ2vc28obhvfham8wewhh0Z data]# docker volume ls
DRIVER    VOLUME NAME(卷名字,这个一串乱码其实是真实存在的目录)
local     dd3decdb4e2533d16d216ba19d8797c2ad95b4a2a1b6a90f87eb98bbed3b3758
# 注:这里发现,这种就是匿名挂载,我们在 -v只写了容器内的路径,没有写容器外的路径!

#2. 具名挂载
#2-1. 使用命令具名挂载
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
# 注1:juming-nginx:/etc/nginx,给/etc/nginx命名为juming-nginx,并没有写主机地址哈
# 注2:说白了就是 -v 卷名:容器内路径

#2-2. 查看一下这个卷
[root@iZ2vc28obhvfham8wewhh0Z data]# docker volume inspect juming-nginx
[
    {
        "CreatedAt": "2021-06-25T20:18:22+08:00",
        "Driver": "local",
        "Labels": null,
        #注意看这儿:下方就是我们挂载到主机的具体路径了
        "Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data",
        "Name": "juming-nginx",
        "Options": null,
        "Scope": "local"
    }
]

所有的docker容器内的卷,没有指定目录的情况下都是在**/var/lib/docker/volumes/自定义的卷名/_data下,咱们使用最多的也是具名挂载**。

总结:

# 三种挂载: 匿名挂载、具名挂载、指定路径挂载
-v 容器内路径			#匿名挂载
-v 卷名:容器内路径		  #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载 docker volume ls 是查看不到的

拓展:

# 通过 -v 容器内路径: ro rw 改变读写权限
ro #readonly 只读
rw #readwrite 可读可写
$ docker run -d -P --name nginx05 -v juming:/etc/nginx:ro nginx
$ docker run -d -P --name nginx05 -v juming:/etc/nginx:rw nginx

# ro 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作!
2-4.初始Dockerfile

Dockerfile 就是用来构建docker镜像的构建文件!它即是命令脚本!先体验一下!

通过这个脚本可以生成镜像,镜像是一层一层的,脚本是一个个的命令,每个命令都是一层!

#1. 在主机/home目录下创建一个dockerfile文件,名字可以随便,这里建议dockerfile
[root@iZ2vc28obhvfham8wewhh0Z home]# mkdir dockerfile
#2. 然后进入dockerfile文件夹
[root@iZ2vc28obhvfham8wewhh0Z home]# cd dockerfile/

#3. 我们在dockerfile文件夹里边写一个脚本文件
[root@iZ2vc28obhvfham8wewhh0Z dockerfile]# vim dockerfile1

dockerfile1:内部内容如下:

# dockerfile1内部内容如下,每个命令就是一层:
FROM centos 					# 当前这个镜像是以centos为基础的
#这里与阿狂不同,不加斜杠死活运行不了
#VOLUME ["volume01","volume02"] 	
VOLUME ["/volume01","/volume02"]	# 挂载卷的卷目录列表(多个目录)

CMD echo "-----end-----"		# 输出一下用于测试

CMD /bin/bash					# 默认走bash控制台
#4. 使用脚本去创建自己的镜像
# 命令解释:
-f dockerfile1 			# f代表file,指这个当前文件的地址(这里是当前目录下的dockerfile1)
-t caoshipeng/centos 	# t就代表target,指目标目录(注意caoshipeng镜像名前不能加斜杠‘/’)
. 						# 表示生成在当前目录下
#--------------------------------------------------------------
[root@iZ2vc28obhvfham8wewhh0Z dockerfile]# docker build -f dockerfile1 -t xixi/centos .
Sending build context to Docker daemon  2.048kB
Step 1/4 : FROM centos #我们自己写的
 ---> 300e315adb2f
Step 2/4 : VOLUME ["/volume01","/volume02"] #我们自己写的
 ---> Running in f2d6c4400114
Removing intermediate container f2d6c4400114
 ---> 060cfd84e017
Step 3/4 : CMD echo "-----end-----" #我们自己写的
 ---> Running in 871b9a8bb9c0
Removing intermediate container 871b9a8bb9c0
 ---> 4c71c64c5cc6
Step 4/4 : CMD /bin/bash #我们自己写的
 ---> Running in 1f30a125b5ff
Removing intermediate container 1f30a125b5ff
 ---> 0db8611ac208
Successfully built 0db8611ac208
Successfully tagged haha/centos:latest

#5. 查看镜像,发现自己创建的镜像成功,名为xixi/centos
[root@iZ2vc28obhvfham8wewhh0Z dockerfile]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
#看!haha/centos,创建完毕
xixi/centos           latest    0db8611ac208   2 minutes ago   209MB
tomcat                9         6654503f1940   46 hours ago    667MB
mysql                 5.7       09361feeb475   2 days ago      447MB
nginx                 latest    d1a364dc548d   4 weeks ago     133MB
tomcat                latest    c43a65faae57   6 weeks ago     667MB
mysql                 latest    c0cdc95609f1   6 weeks ago     556MB
portainer/portainer   latest    580c0e4e98b0   3 months ago    79.1MB
hello-world           latest    d1165f221234   3 months ago    13.3kB
centos                latest    300e315adb2f   6 months ago    209MB
elasticsearch         7.6.2     f29a1ee41030   15 months ago   791MB

image-20210626121457789

#6. 我们查看一下目录

image-20210626131445846

这个卷一定和外部有一个同步的目录!咱们之前写的是匿名挂载,如图:

#7. 查看一下卷挂载的路径,如下图所示:
docker inspect 自定义的镜像名字

image-20210627175015936

假设构建镜像时候没有挂载卷,要手动镜像挂载 -v 卷名:容器内路径!

3-数据卷容器

说白了就是利用容器去给其他容器进行共享数据

比如:多个MySQL同步数据

image-20210627182215194

  • 父容器:A去挂载B,那么B就是A的父容器
  • 数据卷容器:被挂载的容器

测试:

#1. 测试 启动3个容器,通过刚才自己写的镜像启动
# 启动第一个centos,注意版本如果不写默认是找最新版
[root@iZ2vc28obhvfham8wewhh0Z dockerfile]# docker run -it --name docker0001 6ce95e6fc524
[root@d07b05bae720 /]# ls -l
total 0
lrwxrwxrwx   1 root root   7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x   5 root root 360 Jun 27 10:58 dev
drwxr-xr-x   1 root root  66 Jun 27 10:58 etc
drwxr-xr-x   2 root root   6 Nov  3  2020 home
lrwxrwxrwx   1 root root   7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx   1 root root   9 Nov  3  2020 lib64 -> usr/lib64
drwx------   2 root root   6 Dec  4  2020 lost+found
drwxr-xr-x   2 root root   6 Nov  3  2020 media
drwxr-xr-x   2 root root   6 Nov  3  2020 mnt
drwxr-xr-x   2 root root   6 Nov  3  2020 opt
dr-xr-xr-x 156 root root   0 Jun 27 10:58 proc
dr-xr-x---   2 root root 162 Dec  4  2020 root
drwxr-xr-x  11 root root 163 Dec  4  2020 run
lrwxrwxrwx   1 root root   8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x   2 root root   6 Nov  3  2020 srv
dr-xr-xr-x  13 root root   0 Jun 27 10:58 sys
drwxrwxrwt   7 root root 145 Dec  4  2020 tmp
drwxr-xr-x  12 root root 144 Dec  4  2020 usr
drwxr-xr-x  20 root root 262 Dec  4  2020 var
# 容器数据卷在此
drwxr-xr-x   2 root root   6 Jun 27 10:58 volume01
drwxr-xr-x   2 root root   6 Jun 27 10:58 volume02

#2. ctrl+p+q退出容器

#3. 创建第二个容器docker0002,继承docker0001
[root@iZ2vc28obhvfham8wewhh0Z dockerfile]# docker run -it --name docker0002 --volumes-from docker0001 xixi/centos
[root@77e4999257f6 /]# ls -l
total 0
lrwxrwxrwx   1 root root   7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x   5 root root 360 Jun 27 11:02 dev
drwxr-xr-x   1 root root  66 Jun 27 11:02 etc
drwxr-xr-x   2 root root   6 Nov  3  2020 home
lrwxrwxrwx   1 root root   7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx   1 root root   9 Nov  3  2020 lib64 -> usr/lib64
drwx------   2 root root   6 Dec  4  2020 lost+found
drwxr-xr-x   2 root root   6 Nov  3  2020 media
drwxr-xr-x   2 root root   6 Nov  3  2020 mnt
drwxr-xr-x   2 root root   6 Nov  3  2020 opt
dr-xr-xr-x 158 root root   0 Jun 27 11:02 proc
dr-xr-x---   2 root root 162 Dec  4  2020 root
drwxr-xr-x  11 root root 163 Dec  4  2020 run
lrwxrwxrwx   1 root root   8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x   2 root root   6 Nov  3  2020 srv
dr-xr-xr-x  13 root root   0 Jun 27 11:02 sys
drwxrwxrwt   7 root root 145 Dec  4  2020 tmp
drwxr-xr-x  12 root root 144 Dec  4  2020 usr
drwxr-xr-x  20 root root 262 Dec  4  2020 var
drwxr-xr-x   2 root root   6 Jun 27 10:58 volume01
drwxr-xr-x   2 root root   6 Jun 27 10:58 volume02

#4. 在docker0001中的volume01中创建文件,然后在docker0002中的volume01中查看,如下图

image-20210627191044818

#5. 继续测试,创建一个docker0003,继承于docker0001,然后创建一个文件去查看docker0001的变化
#直接说结论:
#1. docker0003创建的文件,docker0001可以查询到,说明容器之间的数据形成了共享(本质是双向拷贝)
#2. 此时删除或者停掉docker0001,我们查看docker0002和docker0003的数据依旧能够查询到,说明数据形成了共享(本质是双向拷贝,容器之间的相互数据拷贝)
#3. 只要有一个容器还在用这组数据就不会丢失,很nice

结论:

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

但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的

八、DockerFile

1-dockerfile介绍

dockerfile是用来构建docker镜像的文件!命令参数脚本!

构建步骤:

构建步骤:

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

我们查看一下官方是怎么做的,每一个镜像都是dockerfile构建的

image-20210627193653045

注意看下图中红框部分,全是命令,一个命令一层,还记得吗

image-20210627193718355

很多官方镜像都是基础包,很多功能没有,我们通常会自己搭建自己的镜像!比如:centos+jdk+tomcat+redis等等

官方既然可以制作镜像,那我们也可以!

2-dockerfile构建过程

基础知识

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

image-20210627194315246

  • Dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件,这个文件十分简单!

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

  • DockerFile:构建文件,定义了一切的步骤,源代码

  • DockerImages:通过DockerFile构建生成的镜像,最终发布和运行产品。原来是一个jar包或者war包,之后我们都要整成docker镜像来使用

  • Docker容器:容器就是镜像运行起来提供服务。

3-DockerFile的指令

FROM				# from:基础镜像,一切从这里开始构建
MAINTAINER			# maintainer:镜像是谁写的, 姓名+邮箱
RUN					# run:镜像构建的时候需要运行的命令
ADD					# add:步骤,tomcat镜像,这个tomcat压缩包!添加内容 添加同目录
WORKDIR				# workdir:镜像的工作目录
VOLUME				# volume:挂载的目录位置
EXPOSE				# expose:暴露端口配置
CMD					# cmd:指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT			# entrypoint:指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD				# onbuild:当构建一个被继承DockerFile这个时候就会运行onbuild的指令,是触发指令
COPY				# copy:类似ADD,将我们文件拷贝到镜像中
ENV					# env:构建的时候设置环境变量!

image-20210627201927569

4-CMD和ENTRYPOINT命令的区别

CMD					# 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代。
ENTRYPOINT			# 指定这个容器启动的时候要运行的命令,可以追加命令

测试CMD:

#1. 编写dockerfile文件
[root@iZ2vc28obhvfham8wewhh0Z dockerfile]# vim dockerfile-test-cmd
#dockerfile-test-cmd的内容如下:
#---------------------
FROM centos
CMD ["ls","-a"]					# 启动后执行 ls -a 命令
#---------------------

#2. 构建镜像
[root@iZ2vc28obhvfham8wewhh0Z dockerfile]# docker build  -f dockerfile-test-cmd -t cmd-test:0.1 .

#3. run命令执行,发现”ls -a“的命令生效
[root@iZ2vc28obhvfham8wewhh0Z dockerfile]# docker run cmd-test:0.1
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

#4. 此时如果我们想追加一个"-l"命令,我们期望能实现"ls -al"的效果
# 动了小脑筋感觉可以这样写“docker run 镜像id -l”,但是这样写是会报错的
[root@iZ2vc28obhvfham8wewhh0Z dockerfile]# docker run cmd-test:0.1 -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.

#分析:在使用cmd的情况下“-l”替换了CMD的["ls","-a"]命令,但是“-l”不是命令,所以报错

#请带着这个问题去测试ENTRYPOINT

测试ENTRYPOINT:

#1. 编写dockerfile文件
vim dockerfile-test-entrypoint
#dockerfile-test-entrypoint的内容如下:
#---------------------
FROM centos
ENTRYPOINT ["ls","-a"]	#这里与之前不一样哦(☆)
#---------------------

#2. 构建镜像
docker build  -f dockerfile-test-entrypoint -t entrypoint-test:0.1 .

#3. 运行镜像
docker run entrypoint-test:0.1

#4. 然后重头戏来了,请对照之前的cmd
#我们的命令,是直接拼接在我们得ENTRYPOINT命令后面的
[root@iZ2vc28obhvfham8wewhh0Z dockerfile]# docker run entrypoint-test:0.1 -l
total 0
drwxr-xr-x   1 root root   6 Jun 27 13:13 .
drwxr-xr-x   1 root root   6 Jun 27 13:13 ..
-rwxr-xr-x   1 root root   0 Jun 27 13:13 .dockerenv
lrwxrwxrwx   1 root root   7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x   5 root root 340 Jun 27 13:13 dev
drwxr-xr-x   1 root root  66 Jun 27 13:13 etc
drwxr-xr-x   2 root root   6 Nov  3  2020 home
lrwxrwxrwx   1 root root   7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx   1 root root   9 Nov  3  2020 lib64 -> usr/lib64
drwx------   2 root root   6 Dec  4  2020 lost+found
drwxr-xr-x   2 root root   6 Nov  3  2020 media
drwxr-xr-x   2 root root   6 Nov  3  2020 mnt
drwxr-xr-x   2 root root   6 Nov  3  2020 opt
dr-xr-xr-x 157 root root   0 Jun 27 13:13 proc
dr-xr-x---   2 root root 162 Dec  4  2020 root
drwxr-xr-x  11 root root 163 Dec  4  2020 run
lrwxrwxrwx   1 root root   8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x   2 root root   6 Nov  3  2020 srv
dr-xr-xr-x  13 root root   0 Jun 27 13:13 sys
drwxrwxrwt   7 root root 145 Dec  4  2020 tmp
drwxr-xr-x  12 root root 144 Dec  4  2020 usr
drwxr-xr-x  20 root root 262 Dec  4  2020 var

总结:

#dockerfile-test-cmd的内容如下:
CMD ["ls","-a"]
#dockerfile-test-entrypoint的内容如下:
ENTRYPOINT ["ls","-a"]

#使用追加命令,CMD不行,ENTRYPOINT可以!
#ENTRYPOINT大胜利!!!

5-实战测试

Dockerhub中99%的镜像都是由FROM scratch开始的,然后配置需要的软件和配置来进行构建。

image-20210627202222266

5-1.创建一个自己的centos

#1./home下新建dockerfile目录,并进入
[root@iZ2vc28obhvfham8wewhh0Z home]# mkdir dockerfile
[root@iZ2vc28obhvfham8wewhh0Z home]# cd dockerfile/

#2. dockerfile目录下新建mydockerfile-centos文件,填写内容如下:
[root@iZ2vc28obhvfham8wewhh0Z dockerfile]# vim mydockerfile-centos

mydockerfile-centos内容如下:

FROM centos							# 基础镜像是官方原生的centos
MAINTAINER peng<951770031@qq.com> 	# 作者

ENV MYPATH /usr/local				# 配置环境变量的目录 
WORKDIR $MYPATH						# 将工作目录设置为 MYPATH

RUN yum -y install vim				# 给官方原生的centos 增加 vim指令
RUN yum -y install net-tools		# 给官方原生的centos 增加 ifconfig命令

EXPOSE 80							# 暴露端口号为80

CMD echo $MYPATH					# 输出下 MYPATH 路径
CMD echo "-----end----"				
CMD /bin/bash						# 启动后进入 /bin/bash
#3. 通过mydockerfile-centos文件构建镜像
#语法:docker build -f dockerfile的文件路径 -t 镜像名:[tag] .

[root@iZ2vc28obhvfham8wewhh0Z dockerfile]# docker build -f mydockerfile-centos -t mycentos:0.1 .
#返回以下信息,表示创建成功
Successfully built f6d21f2d2179
Successfully tagged mycentos:0.1

#4. 查看我们构建的镜像
[root@iZ2vc28obhvfham8wewhh0Z dockerfile]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
mycentos              0.1       f6d21f2d2179   3 minutes ago   295MB
xixi/centos           latest    6ce95e6fc524   2 hours ago     209MB
haha/centos           latest    0db8611ac208   33 hours ago    209MB

#5. 使用run命令启动,发现可以使用vim以及ifconfig命令,与之前的阉割版centos完全不同(不再演示)

#6. 查看镜像的构建过程,看它如何一步步的构建的(不再演示)
#命令:docker history 镜像id

5-2.创建Tomcat镜像

  1. 准备镜像文件:准备tomcat和jdk的压缩包!创建一个文件夹放入安装包/home/hahapeng

image-20210628161618604

  1. 编写dockerfile文件:如果dockerfile的名称为"Dockerfile",build会自动找寻这个文件,不需要再去使用"-f"指定
#1. 创建Dockerfile文件,官方建议名称为Dockerfile
[root@iZ2vc28obhvfham8wewhh0Z hahapeng]# vim Dockerfile

#Dockerfile的内容如下:
#-----------------------------------
# 基础镜像centos
FROM centos

# 作者信息编写
MAINTAINER peng<951770031@qq.com>

# 复制当前目录下readme.txt文件,到容器/usr/local中
COPY readme.txt /usr/local/readme.txt 	

# 添加jdk,ADD 命令会自动解压到/usr/local目录 	
ADD jdk-8u291-linux-x64.tar.gz /usr/local/ 

# 添加tomcat,ADD 命令会自动解压到/usr/local目录 	
ADD apache-tomcat-9.0.46.tar.gz /usr/local/ 

# 安装 vim 命令
RUN yum -y install vim	

# 设置MYPATH
ENV MYPATH /usr/local 

# 工作目录,引用MYPATH
WORKDIR $MYPATH

# 配置环境变量:JAVA_HOME环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_291 

# 配置CLASSPATH
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

# 环境变量: tomcat环境变量
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.46
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.46

# 设置环境变量 分隔符是:
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin 	

# 设置暴露的端口
EXPOSE 8080 										

# 设置默认命令,这里设置了启动指定目录下的startup.sh程序以及日志
CMD /usr/local/apache-tomcat-9.0.46/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.46/logs/catalina.out 					
#-----------------------------------

#2. 创建一个readme.txt的文件
touch readme.txt

  1. 构建镜像
# 因为我们之前用的"Dockerfile"作为名称,因此不用使用-f 指定文件
docker build -t hahatomcat:0.1 .
# 然后漫长的等待,直到返回如下信息:
Successfully built e40a2847610d
Successfully tagged hahatomcat:0.1
  1. run镜像
# -d:后台运行 -p:暴露端口 --name:别名 -v:绑定路径(挂载)
docker run -d -p 8080:8080 --name tomcat01 
-v /home/kuangshen/build/tomcat/test:/usr/local/apache-tomcat-9.0.46/webapps/test 
-v /home/kuangshen/build/tomcat/tomcatlogs/:/usr/local/apache-tomcat-9.0.46/logs hahatomcat:0.1

#以后我们直接把写的项目复制到挂载的目录下,就自动的同步到容器中了,非常方便

  1. 访问测试
docker exec -it 自定义容器的id /bin/bash
cul localhost:8080
  1. 发布项目

由于做了卷挂载,我们直接在本地(挂载位置)编写项目就可以发布了!

发现:项目部署成功,可以直接访问!

我们以后开发的步骤:需要掌握Dockerfile的编写!我们之后的一切都是使用docker镜像来发布运行!

九、发布自己的镜像

1-发布到dockerhub

  1. 去dockerhub官方网站注册账号https://hub.docker.com/
  2. 确定此账号是可以登录的
  3. 在xshell里边进行登录:
#1. 输入登录命令
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker login -u lemonyuki
#2. 弹出提示输入密码,密码输入不会显示
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
#3. 登录成功
Login Succeeded
[root@iZ2vc28obhvfham8wewhh0Z ~]# 
  1. 然后我们进行镜像的发布操作
#1. 查看镜像
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
hahatomcat            0.1       e40a2847610d   18 hours ago    646MB
...

#2. 重命名镜像
# 一般来说我们采用“账号ID名字/镜像名字:[tag]”的格式,这样能保证不重名,docker就能发布成功
# 修改名称的语法:docker tag 原镜像名称:tag 新镜像名称:tag

#将hahatomcat修改为lemonyuki/hahatomcat
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker tag hahatomcat:0.1 lemonyuki/hahatomcat:0.1


#3. 再次查看镜像,发现名称修改成功(本质应该是新建镜像)
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker images
REPOSITORY             TAG       IMAGE ID       CREATED         SIZE
lemonyuki/hahatomcat   0.1       e40a2847610d   19 hours ago    646MB
hahatomcat             0.1       e40a2847610d   19 hours ago    646MB
...

#4. 我们再次push镜像,成功!
#吐槽:push了我一年草,太慢了,吃了个饭都没push好
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker push lemonyuki/hahatomcat:0.1
The push refers to repository [docker.io/lemonyuki/hahatomcat]
4210e5dcae85: Pushed 
1016adb67e5a: Pushed 
fe0df3a669d3: Pushed 
7a2caadd01d0: Pushed 
2653d992f4ef: Pushed 
0.1: digest: sha256:384dc321b5bc31aabf5d1af8e7d5d10d49fcea85b1b97b10c44fe15313905967 size: 1373

2-发布到 阿里云镜像服务上

  1. 登录阿里云
  2. 找到容器镜像服务

image-20210629122310115

  1. 如果有创建个人实例就创建,然后设置镜像仓库的密码

image-20210629122241294

  1. 创建容器命名空间

image-20210629122621803

  1. 创建镜像仓库,然后选择本地仓库即可

image-20210629122803631

image-20210629122817258

  1. 点击你创建的仓库,即可在阿里云官网看到使用方法

image-20210629122936764

开始操作

#1. 首先咱们登录
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker login --username=长门只有a registry.cn-hangzhou.aliyuncs.com
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded

#2. 然后咱们push
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker tag e40a2847610d registry.cn-hangzhou.aliyuncs.com/lemonyuki/lemontest:0.1
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker push registry.cn-hangzhou.aliyuncs.com/lemonyuki/lemontest:0.1

3-小结

现在看这个图,问题不大。图中的save和load是本地的镜像压缩备份,我们一般选择push直接上传到dockerhub或者阿里云

img

十、Docker 网络

1-理解Docker0

学习之前清空下前面的docker 镜像、容器

# 删除全部容器
$ docker rm -f $(docker ps -aq)

# 删除全部镜像
$ docker rmi -f $(docker images -aq)

测试:

image-20210629132904355

这里有三个网络

问题: docker 是如何处理容器网络访问的?

比如现在有一个tomcat,它是如何连接到mysql的

image-20210629133056578

#1. 咱们现在来启动一个tomcat
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker run -d -P --name tomcat01 tomcat
#启动完毕之后,我们思考一下能不能ping通

#2. 查看容器内部网络地址
#语法:docker exec -it 容器id ip addr
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker exec -it bb3980f7b3fb ip addr
#结果如下图所示:
#发现容器启动的时候会得到一个 eth0@if61 的ip地址,这个是docker分配的,每个容器都会有这样的一个地址!

image-20210629134223214

#然后咱们思考:linux能不能ping通容器内部! 可以 容器内部可以ping通外界吗? 可以!
[root@iZ2vc28obhvfham8wewhh0Z ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.061 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.058 ms

2-原理

我们每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要安装了docker,就会有一个网卡docker0(桥接模式),使用的技术是veth-pair技术!

  1. 我们测试ip addr,发现多了一个60和61什么的

image-20210629135225375

  1. 我们再启动一个tomcat02,发现又多了一个63和62

image-20210629135523753

image-20210629140122257

  1. 小结:
#我们发现这个容器带来网卡,都是一对对的
# veth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连
# 正因为有这个特性 veth-pair 充当一个桥梁,连接各种虚拟网络设备的
# OpenStac,Docker容器之间的连接,OVS的连接,都是使用veth-pair技术
  1. 我们再来尝试一下容器之间能否ping通,结论:可以ping通!直接画图理解:
#情况一:路由器可以直接去访问容器

image-20210629143320599

#情况二:容器之间的访问,比如Tomcat01去访问Tomcat02,路由器就是作为一个中间商

image-20210629143448121

  1. 结论:
#Tomcat01和Tomcat02是共用的一个路由器,docker0
#所有的容器不指定网络的情况下,都是docker0路由的,docker会给我们的容器分配一个默认的可用ip

3-小结

Docker使用的是Linux的桥接,宿主机是一个Docker容器的网桥 docker0,如下图所示:

image-20210629144038339

Docker中所有网络接口都是虚拟的,虚拟的转发效率高(比如:内网传递文件)

只要容器删除,对应的网桥一对就没了!

4-命令:–link

思考一个场景:我们编写了一个微服务,我们以前连接数据库都是database url=ip: 项目不重启,数据ip换了,我们希望可以处理这个问题,可以通过名字来进行访问容器

4-1.使用
# 1.发现问题:使用名字去ping,ping不通
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known

#2. 我们再次启动一个tomcat03,但是使用一个"--link"命令与tomcat02连接启动
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker run -d -P --name tomcat03 --link tomcat02 tomcat

#3. 然后我们使用ping命令看看tomcat03和tomcat02之间能否ping通,成功!
#注意:我们是直接使用的名字去ping
[root@iZ2vc28obhvfham8wewhh0Z ~]# 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.096 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.072 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=3 ttl=64 time=0.086 ms
...

#4. tomcat02去ping tomcat02不能ping通,失败!
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known
4-2.探究
#1. 查看网络
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
a46c8b6812aa   bridge    bridge    local
eb05dd76e396   host      host      local
f5d08c983d19   none      null      local

#2. 查看一下bridge的信息,如下图所示
#语法:docker network inspect 网络id 
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker network inspect a46c8b6812aa

image-20210629150136355

image-20210629150227664

#3. 我们查看一下tomcat03的信息,如下:
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker inspect a49e4b731970

image-20210629150734497

#4. 我们还可以去/etc/hosts查询到绑定的信息
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker exec -it tomcat03 cat /etc/hosts

image-20210629151150516

-–link 本质就是在hosts配置中添加映射,现在使用Docker已经不建议使用–-link了!

我们现在需要高级的东西,即自定义网络,就不使用docker0了!因为docker0有问题:即不支持使用容器名连接访问!

5-自定义网络

查看所有的docker网络:

image-20210629152140940

网络模式:

  • bridge :桥接 docker(默认,自己创建也是用bridge模式)
  • none :不配置网络,一般不用
  • host :和宿主机共享网络
  • container :容器网络连通(用得少!局限很大)

测试:

# 我们直接启动的命令 --net bridge,而这个就是我们的docker0
# bridge就是docker0
#"--net bridge"就是默认参数
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat01 --net bridge tomcat
#------------------------------------------------------
#------------------------------------------------------

#自定义网络:

#1. 清理环境,删除之前的容器
docker rm -f  $(docker ps -aq)

#2. 创建一个子网为“192.168.0.0/16”,网关(路由)为“192.168.0.1”,网络名字为“mynet”的网络
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet

#3. 查看创建的网络
docker network ls

image-20210629153225325

#4. 创建两个个tomcat使用我们自定义的网络
docker run -d -P --name tomcat-net-01 --net mynet tomcat
docker run -d -P --name tomcat-net-02 --net mynet tomcat

#5. 然后查看我们自定义的网络,如下图所示
docker network inspect 56505443b59d
#发现容器使用的是我们配置的网络

image-20210629153727271

#6. 我们再来ping容器
docker exec -it tomcat-net-01 ping tomcat-net-02
docker exec -it tomcat-net-01 ping 192.168.0.3

image-20210629154102155

我们自定义的网络docker当我们维护好了对应的关系,推荐我们平时这样使用网络!

好处:

  • redis -不同的集群使用不同的网络,可以保证集群是安全和健康的
  • mysql-不同的集群使用不同的网络,可以保证集群是安全和健康的

6-网络连通

原理:

image-20210629160757943

测试:

#语法:docker network connect [OPTIONS] NETWORK CONTAINER
#1. 之前删除的tomcat01和tomcat02创建好
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat02 tomcat

#2. 打通tomcat01和mynet
docker network connect mynet tomcat01

#3. 查看网络配置,如下图所示:
docker network inspect mynet
# 要将tomcat01 连通 tomcat—net-01 ,连通就是将 tomcat01加到 mynet网络
# 一个容器两个ip(tomcat01)

image-20210629161536014

#4. 现在我们再ping一下
[root@iZ2vc28obhvfham8wewhh0Z ~]# docker exec -it tomcat01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.101 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.083 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.079 ms

**结论:**假设要跨网络操作别人,就需要使用docker network connect 连通!

7-实战:部署Redis集群

image-20210629163936574

#1. 先移除之前的容器
docker rm -f $(docker ps -aq)

#2. 创建redis的网卡
docker network create redis --subnet 172.38.0.0/16

#3. 通过脚本去写配置文件
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.13.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done

#4. 通过脚本创建六个redis文件
for port in $(seq 1 6);\
docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.13.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf; \

#5. 然后依次运行
docker exec -it redis-1 /bin/sh 
docker exec -it redis-2 /bin/sh 
docker exec -it redis-3 /bin/sh 
docker exec -it redis-4 /bin/sh 
docker exec -it redis-5 /bin/sh 
docker exec -it redis-6 /bin/sh 

#6. 创建集群
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

十一、SpringBoot微服务打包Docker镜像

  1. 创建springboot项目,然后打包

image-20210629172300218

  1. 创建Dockerfile文件,并填入如下内容:
#通过java8来构建基础镜像
FROM java:8

#将当前目录下的所有jar包拷贝到镜像根目录,并重新命名为app.jar
COPY *.jar /app.jar

CMD ["--server.port=8080"]

#暴露8080端口
EXPOSE 8080

#执行目录下的app.jar,这样我们的jar包就跑起来了
ENTRYPOINT ["java","-jar","app.jar"]

image-20210629181552987

  1. 将jar包和Dockerfile文件上传到服务器中
#1. 然后使用命令建立一个镜像
docker build -t xxxxx:xx  . 
#2. 运行镜像
docker run -d -P --name XXXX
#3. 然后直接访问即可
curl localhost:XXXX/hello

image-20210629194119121

image-20210629194203545以后我们使用了Docker之后,给别人交付就是一个镜像即可!

**预告:如果有很多镜像?100个镜像怎么办?难道还是一个个的去bulid和run吗 **

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值