Docker从入门到精通

这里写自定义目录标题

      • Docker概述
        • Docker为什么会出现?
        • Docker为什么这么火?
        • Docker能干嘛?
      • Docker安装
        • 文档
        • 安装步骤
        • 使用阿里云镜像加速
      • Docker命令
        • 帮助命令
        • 镜像命令
          • 搜索
          • 下载镜像
          • 删除镜像
        • 容器命令
          • 下载centos镜像
          • 启动容器
          • Docker所有运行的容器
          • 退出容器
          • 删除容器
          • 启动、停止容器
        • 其他常用命令
          • 后台启动容器
          • 查看日志命令
          • 查看容器进程信息
          • 查看镜像元数据
          • 进入容器
          • 从容器拷贝文件到宿主机
          • 查看容器状态
        • 常用命令小结
        • docker安装Nginx练习
        • docker安装Tomcat练习
        • docker 安装es+kibana练习
      • Docker镜像
        • docker 镜像是什么
        • docker镜像加载原理
        • docker镜像加载原理
        • 分层理解
        • Commit镜像
      • 容器数据卷
        • 什么是数据卷?
        • 使用数据卷
        • MySQL安装练习
        • 具名挂载和匿名挂载
        • 构建镜像
        • 容器间数据同步
      • Docker网络原理
        • 理解docker0
        • --link
        • 自定义网络
        • 网络连通
        • 实战:Redis集群
      • DockerFile
        • dockerFile介绍
        • dockerFile构建过程
        • DockerFile指令
        • 实战测试
        • 实战生成自定义tomcat镜像
        • 发布我的镜像
          • 发布到DockerHub
          • 发布到阿里云镜像
      • IDEA整合docker

Docker概述

Docker为什么会出现?

  • 多套环境(开发环境、准生产环境、生产环境)
  • 环境、版本不一致导致不能运行
  • 配置、部署繁琐

Docker解决了以上问题,以前我们开发都是打个jar或war包交给运维来部署,现在使用Docker会将jar + 环境打包生成个镜像放在镜像仓库,直接下载我们的镜像运行即可。

Docker从入门到精通_第1张图片

Docker的核心思想其实来源于集装箱,每个箱子都是相互隔离的,其中一个箱子出问题不会影响其他箱子。举个例子:

假如我们使用的Linux系统就是这个鲸鱼,没有集装箱的时候,我们不能把毒药和水果放在一起吧,放在一起会出问题的,但是有了集装箱以后,我们可以一个集装箱放水果,一个集装箱放毒药,互不影响。Docker的出现可以让Linux的空间得到极大的利用。

Docker为什么这么火?

Docker是基于Go语言开发的。相比于早期的虚拟机技术,最大的优点就是轻巧!Docker隔离、镜像(比如jdk、mysql、redis…)非常小巧,运行镜像也就几兆,有的甚至几KB。而VMware等动则几个G甚至十几个G。

Docker能干嘛?

DevOps(开发运维)

应用更快速的交付、部署

传统:一堆帮助文档、安装程序

Docker:打包镜像发布测试,一键运行

更便捷的升级和扩容

使用了Docker,部署应用就像搭积木一样

项目打包为一个镜像,扩展服务器A、服务器B…

更简单的系统运维

在容器化之后,我们的开发、测试环境都是高度一致的

更高效的计算资源利用

Docker是内核级别的虚拟化,可以在一个物理机上运行很多的容器实例,服务器的性能可以被压缩到极致!

Docker安装

文档

文档地址:https://docs.docker.com/engine/install/centos/

安装步骤

卸载旧版本

$ sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

安装 yum-utils 包(它提供 yum-config-manager 实用工具)并设置稳定存储库。

sudo yum install -y yum-utils

设置默认仓库

$ sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo #默认是国外的
    
sudo yum-config-manager --add-repo \
		http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo #阿里云镜像

安装最新版本的 Docker Engine 和 containerd, docker-ce社区版,docker-ee企业版

$ sudo yum install docker-ce docker-ce-cli containerd.io

启动Docker

$ sudo systemctl start docker

通过运行 hello-world 映像来验证 Docker Engine 安装是否正确。

$ sudo docker run hello-world

查看镜像

docker images

卸载Docker

$ sudo yum remove docker-ce docker-ce-cli containerd.io
$ sudo rm -rf /var/lib/docker

使用阿里云镜像加速

登录阿里云

找到 容器镜像服务

如果没有就创建一个

点击镜像加速器

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://maculvvb.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

Docker命令

帮助命令

帮助命令

docker version
docker info
docker --help

帮助文档:https://docs.docker.com/engine/reference/commandline/docker/

镜像命令

文档地址:https://docs.docker.com/engine/reference/commandline/images/

docker images [OPTIONS] [REPOSITORY[:TAG]]
Name, shorthand Default Description
--all , -a 显示所有镜像(默认隐藏当前镜像)
--digests 展示摘要
--filter , -f 基于提供的条件的过滤器输出
--format 使用 Go 模板的漂亮打印图像
--no-trunc 不要截断输出
--quiet , -q 只显示数字 id
搜索

文档地址: https://docs.docker.com/engine/reference/commandline/search/

docker search [OPTIONS] TERM
Name, shorthand Default Description
--automated 只显示自动构建
--filter , -f 基于提供的条件的过滤器输出
--format 使用 Go 模板进行漂亮印刷的搜索
--limit 25 搜寻结果的最大数目
--no-trunc 不要截断输出
--stars , -s 只显示至少 x 颗星星
下载镜像

文档地址:https://docs.docker.com/engine/reference/commandline/push/

docker push [OPTIONS] NAME[:TAG]
Name, shorthand Default Description
--disable-content-trust true 跳过镜像签名
删除镜像

文档地址:https://docs.docker.com/engine/reference/commandline/rmi/

docker rmi [OPTIONS] IMAGE [IMAGE...]
Name, shorthand Default Description
--force , -f 强制删除镜像
--no-prune 不删除无标签的

容器命令

下载centos镜像
docker pull centos
启动容器
docker run [可选参数] image
#参数说明
--name  容器名字
-d 后台方式运行
-it 交互方式运行 进入容器查看内容
-p 指定端口 -p 8080:8080 和主机的端口映射
		-p IP:主机端口:容器端口
		-p 主机端口:容器端口(常用)
		-p 容器端口
		容器端口
-P 随机映射端口
docker run -it centos /bin/bash 
Docker所有运行的容器
docker ps
-a #列出当前正在运行的容器+历史运行过的容器
-n=? #显示最近创建的容器
-q #只显示容器的编号
退出容器
exit #退出并停止容器
Ctrl + P + Q # 容器不停止退出
删除容器
docker rm 容器ID  # 删除指定容器,不能删除正在运行的容器
docker rm -f $(docker ps -aq) #删除所有容器
docker ps -a -q|xargs docker rm #删除所有容器
启动、停止容器
docker start 容器ID # 启动容器
docker restart 容器ID # 重启容器
docker stop 容器ID #停止容器
docker kill 容器ID # 强制停止当前容器

其他常用命令

后台启动容器
docker run -d 镜像名
查看日志命令
docker logs 容器ID
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 logs -tf --tail 10 #查看最新10条日志
查看容器进程信息
docker top 容器ID
查看镜像元数据
docker inspect --help
Options:
  -f, --format string   Format the output using the given Go template
  -s, --size            Display total file sizes if the type is container
      --type string     Return JSON for specified type
docker inspect 0ed9c92a3359
[
    {
        "Id": "0ed9c92a3359a4562115989cc1686f1c28b9e779385e8d5538f7cad4836f6d5f",
        "Created": "2020-07-07T00:36:11.958148146Z",
        "Path": "docker-entrypoint.sh",
        "Args": [
            "mysqld"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 21414,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2020-07-07T00:47:16.979329147Z",
            "FinishedAt": "2020-07-07T00:47:16.63257377Z"
        },
        "Image": "sha256:44a8e1a5c0b27650237907f4e9ee7fccdba0120291d27075e2cb8c8e8a8ec66b",
        "ResolvConfPath": "/var/lib/docker/containers/0ed9c92a3359a4562115989cc1686f1c28b9e779385e8d5538f7cad4836f6d5f/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/0ed9c92a3359a4562115989cc1686f1c28b9e779385e8d5538f7cad4836f6d5f/hostname",
        "HostsPath": "/var/lib/docker/containers/0ed9c92a3359a4562115989cc1686f1c28b9e779385e8d5538f7cad4836f6d5f/hosts",
        "LogPath": "/var/lib/docker/containers/0ed9c92a3359a4562115989cc1686f1c28b9e779385e8d5538f7cad4836f6d5f/0ed9c92a3359a4562115989cc1686f1c28b9e779385e8d5538f7cad4836f6d5f-json.log",
        "Name": "/mymysql",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": [
            "e0bfc0c67ff4d16cc70f83a47fed2f9eba37b8f42ab7db68cadf04da5b5519a1"
        ],
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {
                "3306/tcp": [
                    {
                        "HostIp": "",
                        "HostPort": "3306"
                    }
                ]
            },
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "Capabilities": null,
            "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/4e4d51419c11cb22784160aa0ec2d9439d3c0b96de6c7d60cf8b503871c99859-init/diff:/var/lib/docker/overlay2/d80494f65004d34717bc6c791cbe881729fd2c0846b3f2e0154ffaf95425d1c6/diff:/var/lib/docker/overlay2/ca45ec4c3bd06a2ef9503df96d7ba32912aee58fa9f8f4cfac2c2b28a6358662/diff:/var/lib/docker/overlay2/02f46b0788697cc0cc150afba025648d24c18ce56307a32b9986140f4fe860d4/diff:/var/lib/docker/overlay2/581596595f1448614c334eb470481fc70a638601f1f81ebe63d6ff8f9f45330e/diff:/var/lib/docker/overlay2/404848294a3253d680450f61ee901ed76c63b9339904ba70e5cd505041414e11/diff:/var/lib/docker/overlay2/5cdba39d722214767eb4fc8040f6222e9582330d5e1910cc44898b88906ff403/diff:/var/lib/docker/overlay2/f201bf786f050af48f5b1f0d6c949bf0f7942c4433b3167c57fc80d7a96d8e6d/diff:/var/lib/docker/overlay2/76d7620a0bc93ba249a614d6b4e201982e99fe5285ed81fb68d6957bce6b61df/diff:/var/lib/docker/overlay2/ab95b6395ae0e52ca93a7224d17fabc1c0ce4b4e145908cace83968e6f2716c2/diff:/var/lib/docker/overlay2/4250bddc52068730181d0b22be7c889963582e43806c49c5c26740f948fcaedb/diff:/var/lib/docker/overlay2/79fc77b97e314b9f4f15be663c2df80b23a9ea8004897c0e2f2301e2260f5d67/diff",
                "MergedDir": "/var/lib/docker/overlay2/4e4d51419c11cb22784160aa0ec2d9439d3c0b96de6c7d60cf8b503871c99859/merged",
                "UpperDir": "/var/lib/docker/overlay2/4e4d51419c11cb22784160aa0ec2d9439d3c0b96de6c7d60cf8b503871c99859/diff",
                "WorkDir": "/var/lib/docker/overlay2/4e4d51419c11cb22784160aa0ec2d9439d3c0b96de6c7d60cf8b503871c99859/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [
            {
                "Type": "volume",
                "Name": "86b9eec00f8d1e9cb4a9bce274ab418fd87d7d58d0a15981f45ed4e9a6e19270",
                "Source": "/var/lib/docker/volumes/86b9eec00f8d1e9cb4a9bce274ab418fd87d7d58d0a15981f45ed4e9a6e19270/_data",
                "Destination": "/var/lib/mysql",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
        "Config": {
            "Hostname": "0ed9c92a3359",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "3306/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "MYSQL_ROOT_PASSWORD=123456",
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "GOSU_VERSION=1.7",
                "MYSQL_MAJOR=5.7",
                "MYSQL_VERSION=5.7.18-1debian8"
            ],
            "Cmd": [
                "mysqld"
            ],
            "Image": "mysql:5.7.18",
            "Volumes": {
                "/var/lib/mysql": {}
            },
            "WorkingDir": "",
            "Entrypoint": [
                "docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {}
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "47a98d0324694a55361b2ca5ce2838a648f8023ba1724ac395f74efb978b3e03",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {
                "3306/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "3306"
                    }
                ]
            },
            "SandboxKey": "/var/run/docker/netns/47a98d032469",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "f3310c3928294d7edbc20ec1847b34996ec691e382bf1d4a3ca645e498387c77",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.3",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:03",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "e6ff23e009d3b064d64225694d33eae351285942c60d91d90c3b09834dd85f31",
                    "EndpointID": "f3310c3928294d7edbc20ec1847b34996ec691e382bf1d4a3ca645e498387c77",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.3",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:03",
                    "DriverOpts": null
                }
            }
        }
    }
]
进入容器
docker exec -it 容器ID /bin/bash #进入容器后开启新的终端
docker attach 容器ID # 进入容器正在执行的终端,不会启动新的进程
从容器拷贝文件到宿主机
docker cp 容器ID:容器内路径 宿主机路径
查看容器状态
docker stats

常用命令小结

attach   Attach to a running container   #当前she11下attach 连接指定运行镜像
build   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 fi lesystem   	#查看docker容器变化
events   Get rea1 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 
history   Show the history of an image    #展示一个镜像形成历史
images   List images    #列出系统当前镜像
import   Create a new filesystem image from the contents of a tarba11    #从tar包中的内容创建个新的文件系统映像【对应export】
info   Display system一wide information    #显示系统相关信息
inspect
Return   1ow一1eve1 information on a container    #查看容器详细信息
ki11   Ki11 a running container    # ki11指定docker 容器
load   Load an timage 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 a11 processes within a container    #暂停容器
ps    List containers    #列出容器列表
pu11    Pu11 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    #移除一个或多个镜像【无容器使用该镜像才可删除,否则需删除相关容器才可继续或-f强制删除】
run 	Run a command in a new container 			#创建一个新的容器并运行一个命令
save 		Save an image to a tar archive 		#保存一个镜像为一个tar包【对应1oad】
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 informati on 	#查看docker版本号
wait  	B1ock until a container. stops,then print its exit code 	#截取容器停止时的退出状态值

docker安装Nginx练习

下载镜像

docker pull nginx

启动容器

docker images

docker run -d --name nginx01 -p 3344:80 nginx
# -d 后台运行 
# --name 给容器起个名
# -p 将公网的3344端口暴露给容器的80端口

Docker从入门到精通_第2张图片

docker安装Tomcat练习

下载Tomcat镜像

docker pull tomcat

运行容器

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

docker 安装es+kibana练习

# es暴露的端口十分多
# es十分耗内存
# es的数据一般要挂载到安全目录
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPS="-Xms64m -Xmx512m" elasticsearch:7.6.2

Docker镜像

docker 镜像是什么

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

docker镜像加载原理

UnionFS (联合文件系统)

我们下载的时候看到的一层层就是这个!

UnionFS (联合文件系统) : Union文件系统( UnionFS)是一种分层、 轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtualfilesystem)。Uniqn 文件系统是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等等。

Docker从入门到精通_第3张图片

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

它是一个精简的OS,只需要包含最精简的命令,因为底层使用系统的Kernel,自己只需要提供rootfs就好了

分层理解

所有的Docker镜像都起始于一个基础镜像层 ,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。

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

Docker从入门到精通_第4张图片

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

Docker从入门到精通_第5张图片

上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。
下图中示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7文件5的一个更新版本。

Docker从入门到精通_第6张图片

这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。Docker通过存储弓|擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件 系统。

Linux.上可用的存储引擎有AUFS、Overlay2、 Device Mapper. Btrfs 以及ZFS。顾名思义,每种存储弓|擎都基于Linux中对应的文件系统或者块设备技术,并且每种存储弓|擎都有其独有的性能特点。

Docker在Windows.上仅支持windowsfilter 一种存储引擎,该引擎基于NTFS文件系统之上实现了分层和CoW【1】。

下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。

Docker从入门到精通_第7张图片

特点

Docker镜像是只读的,当容器启动时,一个新的可写层被加载到镜像顶部,这一层就是我们说的容器层,容器之下的叫镜像层!

Docker从入门到精通_第8张图片

Commit镜像

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

docker commit -m="提交的描述信息" -a="作者" 容器ID 目标镜像名:[TAG]

测试commit Tomcat镜像

  • 下载Tomcat镜像

    docker pull tomcat
    
  • 启动

    docker run -d -p 8080:8080 tomcat
    
  • 进入容器

    docker exec -it 885a68576f0a /bin/bash
    
  • 进入webapps

    cd webapps
    

    发现什么都没有

  • 从webapp.dist中拷贝出所有目录到webapps目录下

    cp -r webapps.dist/* webapps
    
  • 现在我就想用想在的容器当做镜像提交

    docker commit -m="tomcat add webapps" -a="youngj" 885a68576f0a  tomcat-youngj:2.0
    

    Docker从入门到精通_第9张图片

容器数据卷

什么是数据卷?

如果数据都存在容器中,那么我把容器删除,所有的数据将全部丢失!需求:数据可以持久化

如:MySQL数据可以存储在本地!

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

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

Docker从入门到精通_第10张图片

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

使用数据卷

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

测试挂载

docker run -it -v /home/ceshi:/home centos /bin/bash
# 启动起来后通过inspect 容器ID 查看

Docker从入门到精通_第11张图片

测试数据同步

image-20200918114159638

MySQL安装练习

docker pull mysql:5.7

启动

-d 后台启动 -p 3310:3306 将公网端口3310与容器3306端口打通

-v 将宿主机/home/data/mysql/conf与容器/etc/mysql/conf.d共享(MySQL配置),

​ 宿主机/home/data/mysql/data与容器/var/lib/mysql共享(MySQL数据)

-e 环境配置

docker run -d -p 3310:3306 \
	-v /home/data/mysql/conf:/etc/mysql/conf.d \
	-v /home/data/mysql/data:/var/lib/mysql \
	-e MYSQL_ROOT_PASSWORD=123456 \
	--name mysql-youngj mysql:5.7

测试数据是否同步到本地

# 容器中创建数据库
create database youngjdb;

查看本地/home/data/mysql/data中是否有youngjdb

Docker从入门到精通_第12张图片

具名挂载和匿名挂载

  • 匿名挂载

    docker run -d -P --name nginx01 -v /etc/nginx nginx
    # -v 只指定了容器内部的地址 没有指定外部的地址
    
    docker volume ls
    

    image-20200918143255830

    这种就是匿名挂载

  • 具名挂载

    docker run -d -P --name nginx01 -v juming-nginx:/etc/nginx nginx
    # -v 卷名:容器内路径 指定了卷名juming-nginx
    

查看卷目录

docker inspect juming-nginx

Docker从入门到精通_第13张图片

总结:

-v 容器内路径 							 #匿名挂载
-v 卷名:容器内路径  					#具名挂载
-v /宿主机路径:容器内路径			#指定路径挂载

拓展:

docker run -d -P --name nginx01 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx01 -v juming-nginx:/etc/nginx:rw nginx

ro			readonly			#只读,只能从宿主机操作
rw			readwrite			#可读可写

构建镜像

DockerFile就是构建docker镜像的构建文件(命令脚本),通过这个脚本可以生成镜像,镜像是一层层的,脚本是一个个的命令,每个命令都是一层。

FROM centos

VOLUME ["volume01","youngj"]

CMD echo "----end-----"

CMD /bin/bash

执行脚本

docker build -f dockerfile1 -t youngj/centos .

Docker从入门到精通_第14张图片

查看镜像

Docker从入门到精通_第15张图片

运行

docker run -it 297ad69c511a /bin/bash

进入youngj文件夹,创建一个contener.txt文件

Docker从入门到精通_第16张图片

通过docker inspect 容器ID命令查看卷挂载的目录

Docker从入门到精通_第17张图片

进入目录查看文件是否生成成功

容器间数据同步

Docker从入门到精通_第18张图片

通过我们自己构建的镜像,启动3个,进行测试

docker run -it --name docker01 youngj/centos

Docker从入门到精通_第19张图片

再启动一个

docker run -it --name docker02 --volumes-from docker01 youngj/centos 
#--volumes-from 实现了数据同步,相当于继承docker01

进入youngj文件夹,创建docker02.txt文件,再去docker01容器查看是否同步成功

在docker01容器中发现docker02.txt同步成功!

再新建一个docker03容器

docker run -it --name docker03 --volumes-from docker01 youngj/centos

再新建docker03.txt,发现docker01、docker02中同步成功!

删除docker01容器,查看docker02、docker03容器中docker01.txt文件是否存在

经测试,数据依然存在!

Docker从入门到精通_第20张图片

Docker网络原理

理解docker0

  • 删除所有镜像、容器

    docker rm -f $(docker ps -aq) # 删除所有容器
    docker rmi -f $(docker images -aq) # 删除所有镜像
    
  • 查看网卡信息

    ip addr
    

    Docker从入门到精通_第21张图片

docker 容器与容器之间是如何网络访问的?

# 下载Tomcat镜像
docker run -d -P --name tomcat01 tomcat

# 查看容器内网络地址, 发现eth0是分配的网卡,172.17.0.3是容器的地址
docker exec -it tomcat01 ip addr
[root@hecs-x-medium-2-linux-20200615101353 logs]# 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
36583: eth0@if36584: <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
# 经测试,宿主机是可以ping通容器的

原理

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

再来看网卡信息 ip addr, 正好对应容器内网卡信息

再启动一个Tomcat

docker run -d -P --name tomcat02 tomcat

查看 ip addr

再查看容器 ip addr

docker exec -it tomcat02 ip addr

Docker从入门到精通_第22张图片

我们发现,这个容器带来的网卡都是一对一对的,

veth-pair 就是一对虚拟设备接口,他们都是成对出现,一端连着协议,一端彼此相连,veth-pair充当于一个桥梁,连接各种网络设备

测试Tomcat02是否能够ping通Tomcat01

docker exec -it tomcat02 ping 172.17.0.3

Docker从入门到精通_第23张图片

结论: Tomcat01 和 Tomcat02是公用的一个路由器,docker0,左右的容器在不指定网络的情况下,都是docker0来路由的,docker会给我们分配一个默认的可用IP!

Docker 使用的是Linux桥接,如下图

Docker从入门到精通_第24张图片

–link

思考一个场景,我们编写了一个微服务,比如mysql的连接地址为:database.url=ip:port,数据库IP换掉了,我们想不重启解决这个问题,可以通过名字访问容器

# Tomcat02 ping Tomcat01时,提示tomcat01: Name or service not known,怎么解决呢?
docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known

#使用 --link
#再启动一个tomcat03
[root@hecs-x-medium-2-linux-20200615101353 logs]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
5b369c8cf0dd227306f0ac3a32a7f0f06d17b20da4bd04a40cc58cecdde72e28
[root@hecs-x-medium-2-linux-20200615101353 logs]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.4) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.4): icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from tomcat02 (172.17.0.4): icmp_seq=2 ttl=64 time=0.058 ms
64 bytes from tomcat02 (172.17.0.4): icmp_seq=3 ttl=64 time=0.050 ms

# 我们发现tomcat03是可以ping通Tomcat02的,那么反过来可以吗?
docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known 

# 反过来是不可以的,其实tomcat3就是在本地配置了tomcat02的配置
docker exec -it tomcat03 cat /etc/hosts
[root@hecs-x-medium-2-linux-20200615101353 logs]# docker exec -it tomcat03 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.17.0.4      tomcat02 53c7169fc50f
172.17.0.5      5b369c8cf0dd

# --link就是在hosts中增加了172.17.0.4      tomcat02 53c7169fc50f
# 我们现在已经不推荐这种方式!!!

docker0不支持自定义网络!

自定义网络

查看所有的docker网络

docker network ls

image-20200921150544983

网络模式

bridge:桥接 docker(默认,自己创建也使用bridge模式)

none:不配置网络

host:和宿主机共享网络

container:容器网络连通(用的少)

测试

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

#docker0的特点:默认,域名不能访问,可以通过--link打通,但是太麻烦,不推荐!

#我们可以自定义一个网络
[root@hecs-x-medium-2-linux-20200615101353 logs]# docker network --help
Usage:  docker network COMMAND
Manage networks
Commands:
  connect     Connect a container to a network
  create      Create a network
  disconnect  Disconnect a container from a network
  inspect     Display detailed information on one or more networks
  ls          List networks
  prune       Remove all unused networks
  rm          Remove one or more networks

# --driver bridge
# --subnet 192.168.0.0/16 (16代表255*255个端口=65535) 192.168.0.2 到 192.168.255.255
# --gateway 192.168.0.1
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
dc07b32aa00eb41f03603c5b46147dd890dcd02c9598b0013d062fd3cea7c75a
[root@hecs-x-medium-2-linux-20200615101353 logs]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
e6ff23e009d3        bridge              bridge              local
798d3792b63c        host                host                local
dc07b32aa00e        mynet               bridge              local
f6279634a0e8        none                null                local

我们自己的网络就建好了

Docker从入门到精通_第25张图片

启动两个tomcat,测试是否互通

# 先启动 tomcat-net-01
docker run -d -P --name tomcat-net-01 --net mynet tomcat
# 再启动 tomcat-net-02
docker run -d -P --name tomcat-net-02 --net mynet tomcat 

# --net 使用我们自己创建的网络
docker exec -it tomcat-net-01 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.047 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.048 ms
# 反向测试
docker exec -it tomcat-net-02 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.028 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.049 ms

我们自定义的网络,docker都已经帮我们维护好了对应关系,推荐这样使用!

好处:

mysql:不同集群使用不同网络,保证集群安全、健康

redis:不同集群使用不同网络,保证集群安全、健康

Docker从入门到精通_第26张图片

网络连通

Docker从入门到精通_第27张图片

如果此时我想tomcat01和tomcat-net-01互通,也就是和mynet打通,怎么操作?

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
docker network connect mynet tomcat01 #将mynet 和 tomcat01打通
[root@hecs-x-medium-2-linux-20200615101353 logs]# docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.059 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.058 ms

查看mynet详情

docker network inspect mynet

Docker从入门到精通_第28张图片

发现mynet Containers中多了一个tomcat01容器!

docker通过一个容器 两个IP方式,如:阿里云公网IP和私网IP,将两个容器打通!

总结:假如我要跨网络操作别人,就需要用docker network connect连接!

实战:Redis集群

Docker从入门到精通_第29张图片

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

# 使用脚本创建6个配置文件
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-1
docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
 -v /mydata/redis/node-1/data:/data \
 -v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
 -d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
# 启动redis-2
docker run -p 6372:6379 -p 16372:16379 --name redis-2 \
 -v /mydata/redis/node-2/data:/data \
 -v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf \
 -d --net redis --ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
 # 启动redis-3
docker run -p 6373:6379 -p 16373:16379 --name redis-3 \
 -v /mydata/redis/node-3/data:/data \
 -v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf \
 -d --net redis --ip 172.38.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
 # 启动redis-4
docker run -p 6374:6379 -p 16374:16379 --name redis-4 \
 -v /mydata/redis/node-4/data:/data \
 -v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf \
 -d --net redis --ip 172.38.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
 # 启动redis-5
docker run -p 6375:6379 -p 16375:16379 --name redis-5 \
 -v /mydata/redis/node-5/data:/data \
 -v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf \
 -d --net redis --ip 172.38.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
 # 启动redis-6
docker run -p 6376:6379 -p 16376:16379 --name redis-6 \
 -v /mydata/redis/node-6/data:/data \
 -v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf \
 -d --net redis --ip 172.38.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
 
# 创建集群
# 随便进入一个容器
docker exec -it redis-1 /bin/sh

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

>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.38.0.15:6379 to 172.38.0.11:6379
Adding replica 172.38.0.16:6379 to 172.38.0.12:6379
Adding replica 172.38.0.14:6379 to 172.38.0.13:6379
M: 1f7c20e84a30b48a98e196bfaa2a8229321614aa 172.38.0.11:6379
   slots:[0-5460] (5461 slots) master
M: 7aeb822b2771d4f2ceafef662684486ec6b7db70 172.38.0.12:6379
   slots:[5461-10922] (5462 slots) master
M: 6c8d11c99dc37ba11bbe23465a578ac25cefae21 172.38.0.13:6379
   slots:[10923-16383] (5461 slots) master
S: a165daef5112eccf35afba2e9f0df60eb68a13ef 172.38.0.14:6379
   replicates 6c8d11c99dc37ba11bbe23465a578ac25cefae21
S: 6bd4754e3c2cfc68dc7d34167292c1af4c1a5853 172.38.0.15:6379
   replicates 1f7c20e84a30b48a98e196bfaa2a8229321614aa
S: 7b81af71af3cbe4f2340b2146f4d8a78cc3cb143 172.38.0.16:6379
   replicates 7aeb822b2771d4f2ceafef662684486ec6b7db70

Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
...
>>> Performing Cluster Check (using node 172.38.0.11:6379)
M: 1f7c20e84a30b48a98e196bfaa2a8229321614aa 172.38.0.11:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: 6bd4754e3c2cfc68dc7d34167292c1af4c1a5853 172.38.0.15:6379
   slots: (0 slots) slave
   replicates 1f7c20e84a30b48a98e196bfaa2a8229321614aa
M: 7aeb822b2771d4f2ceafef662684486ec6b7db70 172.38.0.12:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: a165daef5112eccf35afba2e9f0df60eb68a13ef 172.38.0.14:6379
   slots: (0 slots) slave
   replicates 6c8d11c99dc37ba11bbe23465a578ac25cefae21
S: 7b81af71af3cbe4f2340b2146f4d8a78cc3cb143 172.38.0.16:6379
   slots: (0 slots) slave
   replicates 7aeb822b2771d4f2ceafef662684486ec6b7db70
M: 6c8d11c99dc37ba11bbe23465a578ac25cefae21 172.38.0.13:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
                           

测试主从,当主挂了之后,从是否会成为主

/data # redis-cli -c

# 查看集群信息
172.38.0.13:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:3
cluster_stats_messages_ping_sent:568
cluster_stats_messages_pong_sent:568
cluster_stats_messages_meet_sent:3
cluster_stats_messages_sent:1139
cluster_stats_messages_ping_received:566
cluster_stats_messages_pong_received:571
cluster_stats_messages_meet_received:2
cluster_stats_messages_received:1139

#查看节点信息
172.38.0.13:6379> CLUSTER nodes
7b81af71af3cbe4f2340b2146f4d8a78cc3cb143 172.38.0.16:6379@16379 slave 7aeb822b2771d4f2ceafef662684486ec6b7db70 0 1600681888561 6 connected
1f7c20e84a30b48a98e196bfaa2a8229321614aa 172.38.0.11:6379@16379 master - 0 1600681887000 1 connected 0-5460
6c8d11c99dc37ba11bbe23465a578ac25cefae21 172.38.0.13:6379@16379 myself,master - 0 1600681888000 3 connected 10923-16383
a165daef5112eccf35afba2e9f0df60eb68a13ef 172.38.0.14:6379@16379 slave 6c8d11c99dc37ba11bbe23465a578ac25cefae21 0 1600681887057 4 connected
7aeb822b2771d4f2ceafef662684486ec6b7db70 172.38.0.12:6379@16379 master - 0 1600681888561 2 connected 5461-10922
6bd4754e3c2cfc68dc7d34167292c1af4c1a5853 172.38.0.15:6379@16379 slave 1f7c20e84a30b48a98e196bfaa2a8229321614aa 0 1600681888061 5 connected

# 随便存一个值,发现存在172.38.0.13:6379
127.0.0.1:6379> set a b
-> Redirected to slot [15495] located at 172.38.0.13:6379
OK

# 当172.38.0.13这台服务挂了之后,测试是否能查询到值
# 停掉redis-3
docker stop redis-3

# 重新查询
get a
-> Redirected to slot [15495] located at 172.38.0.14:6379
"b"

# 重新查看节点状态,发现172.38.0.13:6379 fail, 172.38.0.14已经成为了master
172.38.0.14:6379> CLUSTER nodes
7aeb822b2771d4f2ceafef662684486ec6b7db70 172.38.0.12:6379@16379 master - 0 1600682270008 2 connected 5461-10922
6c8d11c99dc37ba11bbe23465a578ac25cefae21 172.38.0.13:6379@16379 master,fail - 1600682209785 1600682208000 3 connected
1f7c20e84a30b48a98e196bfaa2a8229321614aa 172.38.0.11:6379@16379 master - 0 1600682271510 1 connected 0-5460
7b81af71af3cbe4f2340b2146f4d8a78cc3cb143 172.38.0.16:6379@16379 slave 7aeb822b2771d4f2ceafef662684486ec6b7db70 0 1600682272011 2 connected
6bd4754e3c2cfc68dc7d34167292c1af4c1a5853 172.38.0.15:6379@16379 slave 1f7c20e84a30b48a98e196bfaa2a8229321614aa 0 1600682270000 5 connected
a165daef5112eccf35afba2e9f0df60eb68a13ef 172.38.0.14:6379@16379 myself,master - 0 1600682271000 7 connected 10923-16383

DockerFile

dockerFile介绍

dockerFile是用来构建docker镜像的文件。它就是命令脚本!

构建步骤:

1、编写一个dockerFile文件

2、docker build 构建成一个镜像

3、运行镜像

4、docker push 发布镜像(DockerHub、阿里云镜像仓库)

dockerFile构建过程

基础知识

1、每个关键字必须是大写字母

2、执行顺序是从上到下顺序执行

3、#表示注释

4、每一个指令都会创建提交一个新的镜像层,并提交!

Docker从入门到精通_第30张图片

dockerFile是面向开发的,以后发布项目就需要编写dockerFile。

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

DockerImages:通过DockerFile构建生成一个镜像,最终发布运行的产品

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

DockerFile指令

Docker从入门到精通_第31张图片

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

实战测试

编写DockerFile文件

vim dockerfile-centos

# dockerfile内容如下:

FROM centos
MAINTAINER youngJ<[email protected]>

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "----build success----"
CMD /bin/bash 

构建镜像

docker build -f dockerfile-centos -t mycentos:0.1 .
# docker build -f 脚本路径 -t 镜像名:版本号 .

启动

docker run -it mycentos:0.1

测试是否含有vim命令

经测试,含有vim命令!

查看镜像历史构建信息

docker history 镜像ID

Docker从入门到精通_第32张图片

测试CMD命令和ENTRYPOINT的区别

# 编写dockerfile-cmd文件
FROM centos
CMD ["ls", "-a"]

# 构建镜像
docker build -f dockerfile-cmd -t dockerfilecmd:0.1 . 

# 启动镜像
 docker run dockerfilecmd:0.1
 [root@hecs-x-medium-2-linux-20200615101353 dockerFile]# docker run dockerfilecmd:0.1
.
..
.dockerenv
bin
dev
etc
home
...
# 想追加一个指令 ls -al
docker run dockerfilecmd:0.1 -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.

测试ENTRYPOINT命令

# 编写dockerfile-entrypoint文件
FROM centos
ENTRYPOINT ["ls", "-a"]

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

#启动镜像
docker run dockerfile-entrypoint:0.1
[root@hecs-x-medium-2-linux-20200615101353 dockerFile]# docker run dockerfile-entrypoint:0.1
.
..
.dockerenv
bin
dev
etc
home
lib
lib64

# 追加一个命令 -l    也就是 ls -al
docker run dockerfile-entrypoint:0.1 -l
[root@hecs-x-medium-2-linux-20200615101353 dockerFile]# docker run dockerfile-entrypoint:0.1 -l
total 56
drwxr-xr-x   1 root root 4096 Sep 18 09:30 .
drwxr-xr-x   1 root root 4096 Sep 18 09:30 ..
-rwxr-xr-x   1 root root    0 Sep 18 09:30 .dockerenv
lrwxrwxrwx   1 root root    7 May 11  2019 bin -> usr/bin
drwxr-xr-x   5 root root  340 Sep 18 09:30 dev
drwxr-xr-x   1 root root 4096 Sep 18 09:30 etc
drwxr-xr-x   2 root root 4096 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
...

实战生成自定义tomcat镜像

FROM centos

MAINTAINER youngJ<[email protected]>

ADD jdk-8u251-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.38.tar.gz /usr/local/

RUN yum -y install vim

ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk1.8.0_251
ENV CLASSPATH $JAVA_HOME/lib/dt.jar;$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.38
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.38
ENV PATH $PATH;$JAVA_HOME/bin;$CATALINA_HOME/lib;$CATALINA_HOME/bin

EXPOSE 8080

CMD /usr/local/apache-tomcat-9.0.38/bin/startup.sh && tailf /usr/local/apache-tomcat-9.0.38/logs/catalina.out

build 镜像

docker build -f dockerfile -t mytomcat:2.0 . 

Docker从入门到精通_第33张图片

启动

docker run -d -p 8080:8080 --name mytomcat -v /home/data/tomcat/test:/usr/local/apache-tomcat-9.0.38/webapps/test -v /home/data/tomcat/logs:/usr/local/apache-tomcat-9.0.38/logs mytomcat:2.0

测试目录是否同步成功

image-20200921100933315

新建web.xml

mkdir WEB-INF


<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"%>




youngj


Hello World!
<% System.out.println("你的 IP 地址 " + request.getRemoteAddr()); %>

Docker从入门到精通_第34张图片

发布我的镜像

发布到DockerHub
  • 注册并登陆

    DockerHub官网

  • 使用命令行登陆再提交

    docker login --help
    Options:
      -p, --password string   Password
          --password-stdin    Take the password from stdin
      -u, --username string   Username
    
    docker login -u youngj
    

    Docker从入门到精通_第35张图片

  • 发布

    # 发布我自己定义的tomcat2.0
    docker push mytomcat:2.0
    
    The push refers to repository [docker.io/library/mytomcat]
    aa19e7b28c26: Preparing
    a5f01137bfee: Preparing
    336ebc8bd789: Preparing
    291f6e44771a: Preparing
    denied: requested access to the resource is denied # 被拒绝
    
    #解决:增加一个tag
    # docker tag 镜像ID 作者/镜像名称:版本
    docker tag 4416171521d9 youngj/mytomcat:2.0
    #REPOSITORY    			TAG    IMAGE ID      		   CREATED             SIZE
    #youngj/mytomcat    2.0    4416171521d9        About an hour ago   694MB
    docker push youngj/mytomcat:2.0
    
    [root@hecs-x-medium-2-linux-20200615101353 logs]# docker push youngj/mytomcat:2.0
    The push refers to repository [docker.io/youngj/mytomcat]
    aa19e7b28c26: Pushing [>                                                  ]  1.107MB/57.24MB
    a5f01137bfee: Pushing [==============>                                    ]  4.505MB/15.6MB
    336ebc8bd789: Pushing [>                                                  ]  2.188MB/405.8MB
    291f6e44771a: Pushing [>                                                  ]  2.725MB/215.1MB
    
    
发布到阿里云镜像
  • 登陆阿里云官网

    阿里云官网

  • 找到容器镜像服务

  • 创建命名空间

Docker从入门到精通_第36张图片

  • 查看详情

    Docker从入门到精通_第37张图片

  • 登陆

    docker login --username=用户名 registry.cn-hangzhou.aliyuncs.com
    

  • 打个标签

    docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/youngj/youngj:[镜像版本号]
    
  • 上传

    docker push registry.cn-hangzhou.aliyuncs.com/youngj/mytomcat:2.0
    The push refers to repository [registry.cn-hangzhou.aliyuncs.com/youngj/mytomcat]
    aa19e7b28c26: Pushing [=>                                                 ]  2.221MB/57.24MB
    a5f01137bfee: Pushing [==>                                                ]  703.5kB/15.6MB
    336ebc8bd789: Pushing [>                                                  ]  1.075MB/405.8MB
    291f6e44771a: Pushing [>                                                  ]  1.082MB/215.1MB
    

Docker从入门到精通_第38张图片

IDEA整合docker

  • 新建springboot项目

  • 新建controller

    @RestController
    public class TestController {
        @RequestMapping("/hello")
        public String hello() {
            return "hello! youngJ";
        }
    }
    
  • 新建Dockerfile

    # 基础镜像 Java8
    FROM java:8
    
    # 把所有的jar 放到app.jar中
    COPY *.jar /app.jar
    
    # 指定端口8080
    CMD ["--server.port=8080"]
    
    # 对外暴露端口8080
    EXPOSE 8080
    
    # 执行命令 java -jar /app.jar
    ENTRYPOINT ["java", "-jar", "/app.jar"]
    
  • 构建镜像

将springboot项目package打包与Dockerfile文件放到服务器

docker build -f Dockerfile -t docker-idea:0.0.1 .
  • 运行

    docker run -d -P --name idea-docker docker-idea:0.0.1 
    
  • 查看端口

    [root@hecs-x-medium-2-linux-20200615101353 docker-idea]# docker ps
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
    83ec9d1c32fd        docker-idea:0.0.1   "java -jar /app.jar …"   15 seconds ago      Up 14 seconds       0.0.0.0:32778->8080/tcp   idea-docker 
    
  • 请求接口

    [root@hecs-x-medium-2-linux-20200615101353 docker-idea]# curl localhost:32778/hello
    hello! youngJ
    

下期预告:
Docker进阶版 :Docker compose、Docker swarm、k8s等实战
敬请关注公众号

Docker从入门到精通_第39张图片

你可能感兴趣的:(docker,入门,docker)