一文即懂docker

视频链接

Docker概述

Docker为什么会出现

一款产品:开发-上线 两套环境!应用环境,应用配置!

开发----运维。问题:我在我的电脑上,我可以运行!版本更新,导致服务不可用。

开发即运维!!!!环境配置(集群Redis、Es、Hadoop....)!费时费力

发布一个项目(jar+(Redis MySQL jdk ES)),项目带上环境安装打包!

之前在服务器配置一个应用的环境 Redis MySQL jdk Es Hadoop,配置都很麻烦,不能跨平台。

Windows,最后发布到Linux!

传统:开发jar,运维来做!

现在:开发打包部署上线,一套流程做完!

java -- apk -- 发布 (应用商店) ---- 张三使用apk ---- 安装即可用!

java --- jar(环境)---打包项目带上环境(镜像)---(Docker仓库:商店) ---下载我们发布的镜像---直接运行既可!

Docker给以上的问题提出了解决方案!

Docker的思想就来自于集装箱!

JRE ---多个应用(端口冲突) ---原来都是交叉的!

隔离:Docker核心思想!打包装箱!每个箱子都是互相隔离的。

Docker的历史

2010年,几个搞IT的年轻人,就在美国成立了一家公司dotCloud

做一些pass的云计算服务!LXC有关的容器技术!

他们将自己的技术(容器化技术) 命名 就是Docker!

Docker刚刚诞生的时候,没有引起行业的注意!dotCloud,活不下去!

开源

开发源代码!

2013年,Docker开源!

Docker越来越多的人发现了docker的有点!火了,Docker每个月都会更新一个版本!

2024年4月9日,Docker1.0发布!

Docker为什么这么火?十分的轻巧!

在容器技术出来之前,我们都是使用的虚拟机技术!

虚拟机:在window中装一个Vmware,通过这个软件,我们可以虚拟出来一台或者多台电脑!

虚拟机也是虚拟化技术,Docker容器技术,也是一种虚拟化技术!

vm,Linux centos原生镜像(一台电脑)隔离,需要开启多个虚拟机!几个G

docker,隔离,镜像(最核心的环境4m+jdk+mysql)十分轻巧,运行镜像就可以了!小巧!几个M KB 秒级启动!

每一个开发人员都必须会的一门技术。

Docker是基于Go语言开发的

官网

文档地址

仓库地址

Docker能做什么

虚拟机技术缺点:

1.资源占用十分多

2.重复步骤多

3.启动很慢

容器化技术

容器化技术不是模拟一个完整的操作系统

比较Docker和虚拟机技术的不同:

传统虚拟机:虚拟出一条硬件,运行一个完整的操作系统,然后在这个系统上安装运行软件

容器内的应用直接运行在宿主机的内容,容器是没有自己的内核的,也没有虚拟我们的硬件,所以就轻便了

每个容器之间是相互隔离的,每个容器内都有一个属于自己的文件系统,互不影响。

DevOps(开发、运维)

应用更快速的交付和部署

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

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

更便捷的升级和扩缩容

使用Docker之后,我们部署应用就和搭积木一样

项目打包成一个镜像,扩展 服务器A !服务器B

更简单的系统运维

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

更高效的计算资源利用

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

Docker安装

Docker的基本组成

镜像(image):

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

容器(container):

Docker利用容器技术,独立运行一个或者一个组应用,通过镜像来创建的。

启动,停止,删除,基本命令!

目前就可以把这个容器理解为就是一个简易的linux系统

仓库(repository):

仓库就是存放镜像的地方!

仓库分为公有仓库和私有仓库!

Docker Hub(默认是国外的)

阿里云....都有容器服务器(配置镜像加速!)

安装Docker

环境准备

需要会一点点linux的基础

CentOS7

使用xshell连接远程的服务器进行操作!

环境查看

cat /etc/os-release

查看使用文档

yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
yum install -y yum-utils
yum-config-manager \
    --add-repo \
    http://mirrors.aliyun.com/docker- ce/linux/centos/docker-ce.repo --配置阿里云仓库
yum makecache fast
yum install docker-ce docker-ce-cli containerd.io
systemctl start docker
docker version
docker run hello-world
docker images
#卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
#删除资源
rm -rf /var/lib/docker

# /var/lib/docker   docker的默认工作路径!

阿里云镜像加速

1.登录阿里云

2.进入控制台

3.左边搜索容器镜像服务

4.左边有个镜像加速器

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

desktop for docker的话就是

回顾Hello World流程

底层原理

docker是怎么工作的?

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

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

Docker为什么比VM快

1.Docker有着比虚拟机更少的抽象层。

2.docker利用的是宿主机的内核,vm需要的是Guest OS。

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

Docker的常用命令

帮助命令

docker version #显示docker的版本信息
docker info    #显示docker的系统信息,包括镜像和容器的数量
docker 命令 --help  #万能命令

帮助文档的地址

命令文档地址

镜像命令

docker images

查看所有本地的主机上的镜像

-a,--all              #列出所有镜像
-q,--quiet            #只显示镜像的id
-aq

docker search

搜索镜像

docker search mysql
--filter=STARS=3000   搜索出来的镜像就是STARS大于3000的

docker pull

下载镜像,当搜索到了镜像之后,就可以开始下载镜像了

docker pull mysql:latest
如果不写tag(用来指定版本下载的),那么就默认时latest(最新版)
分层下载的,docker image的核心 联合文件系统
下载后还有一个签名
还有一个真实的地址

docker rmi

删除镜像

docker rmi -f e73346bdf465
docker rmi -f e73346bdf465 e73346bkf231 
docker rmi -f $(docker images -aq)  #这个是删除前部的容器

容器命令

说明:只有当我们有了镜像才可以创建容器,linux ,下一个centos镜像来测试学习

docker pull centos

docker run

新建容器并启动

docker run [可选参数] image
#参数说明
--name="Name" 容器名字   tomcat01 tomcat02(主要用来区分容器)
-d            后台方式运行
-it           使用交互方式运行,进入容器查看内容
-p            指定容器的端口 -p   8080:8080
    -p ip:主机端口:容器端口
    -p 主机端口:容器端口(常用)
    -p 容器端口
-P(大写)     随机指定端口 



#测试(启动、并且进入容器)
[root@iZ2  ~]#docker run -it centos /bin/bash
[root@cd5b /]# ls #查看容器内的centos,基础版本,很多命令都是不完善的
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var


#从容器中退出
[root@cd5b7850a131 /]# exit

docker ps

列出所有正在运行的容器

-a               列出当前正在运行的容器+带出历史运行过的容器
-n=3             显示最近创建的三个容器
-q               只显示容器的编号

退出容器(在容器内部)

exit           #直接容器停止并退出
Ctrl + P + Q   #容器不停止退出

删除容器

docker rm 容器id                   删除指定的容器(不能删除正在运行的容器,如果想,必须使用-f强制删除)
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 centos

注意:
    发现docker ps没有找到centos,原因是容器里面没有一个前台进程,也没有提供任何的服务。就会被停止了。
    

查看日志

docker logs -f -t --tail [10] dce7b86171bf

#自己编写一段shell脚本(目的是保持这个容器一直运行着不停掉)
docker run -d centos /bin/sh -c "while true;do echo kuangshen;slepp 1;done"

#使用docker ps找到需要知道日志的容器ID
-tf     							#要显示日志条数
-tail number     			#要显示的日志条数
docker logs -f -t --tail [10] dce7b86171bf

查看容器中进程信息

docker top dce7b86171bf

查看镜像中的元数据

docker inspect dce7b86171bf
#输出
[
    {
        "Id": "65763ad37c38bc842477179717f83aed5771129eb7697a6ff2f69dd7ea40708d",
        "Created": "2025-03-15T07:46:20.138091413Z",
        "Path": "/usr/sbin/sshd",
        "Args": [
            "-D"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 6605,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2025-03-15T07:46:20.44389666Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:b8fe5db7af94088273c7e3109035fa69a1a16512a988531abecbd9323ad0fa69",
        "ResolvConfPath": "/var/lib/docker/containers/65763ad37c38bc842477179717f83aed5771129eb7697a6ff2f69dd7ea40708d/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/65763ad37c38bc842477179717f83aed5771129eb7697a6ff2f69dd7ea40708d/hostname",
        "HostsPath": "/var/lib/docker/containers/65763ad37c38bc842477179717f83aed5771129eb7697a6ff2f69dd7ea40708d/hosts",
        "LogPath": "/var/lib/docker/containers/65763ad37c38bc842477179717f83aed5771129eb7697a6ff2f69dd7ea40708d/65763ad37c38bc842477179717f83aed5771129eb7697a6ff2f69dd7ea40708d-json.log",
        "Name": "/python",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": [
            "125a660ab3d80c7f5e435405220aaddd5a4ccca6c3a0b45f47ec545a1e9ac975"
        ],
        "HostConfig": {
            "Binds": [
                "/app:/app"
            ],
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "bridge",
            "PortBindings": {
                "22/tcp": [
                    {
                        "HostIp": "",
                        "HostPort": "2222"
                    }
                ],
                "8885/tcp": [
                    {
                        "HostIp": "",
                        "HostPort": "8885"
                    }
                ]
            },
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "ConsoleSize": [
                25,
                159
            ],
            "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",
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": [],
            "BlkioDeviceWriteBps": [],
            "BlkioDeviceReadIOps": [],
            "BlkioDeviceWriteIOps": [],
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "Ulimits": [],
            "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",
                "/sys/devices/virtual/powercap"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/365f99061b8b71aaa6f2b61c1884d0542347695bc311a992035320c3a8652c43-init/diff:/var/lib/docker/overlay2/ewi4ry2pzk0ascl11v5r4tgxp/diff:/var/lib/docker/overlay2/78b880d5bfb71d560c08f2fa6fe611a8f7ed66339bd4b965f6b54203bb2394c9/diff:/var/lib/docker/overlay2/1e9c62b1f386ab29719286c404c644154e3a4ec5317662ccfe33938fbcc3f2d2/diff:/var/lib/docker/overlay2/66f27f903ef1ab63b1da911fb759803061c9b844955a97a02672cbe92dcf9998/diff:/var/lib/docker/overlay2/8fcc3307afdb0d689158dcb134e3667a4bc5a30c6df20b1f6036cecfcb48a6b5/diff:/var/lib/docker/overlay2/18e8d06926087fa48c411580b5100c5cddca83879e12947626d6b1bfda9bc641/diff:/var/lib/docker/overlay2/c241dbdec836c9bc29ee432fd56bd256a5cf082340e3247386c841561669c91f/diff:/var/lib/docker/overlay2/80c50c70f6f1b633e828077540c8ee8b521d4ca1a550b1c4a3a7c4a7cee8e252/diff:/var/lib/docker/overlay2/c903f64a7a8030f650c56c0b3ae469ac6b564e34c4e3893d0e4058a47f862248/diff:/var/lib/docker/overlay2/f6672a7b890478723112afb77f820d2701e911c68f406ec888a2ea3d501b6976/diff",
                "MergedDir": "/var/lib/docker/overlay2/365f99061b8b71aaa6f2b61c1884d0542347695bc311a992035320c3a8652c43/merged",
                "UpperDir": "/var/lib/docker/overlay2/365f99061b8b71aaa6f2b61c1884d0542347695bc311a992035320c3a8652c43/diff",
                "WorkDir": "/var/lib/docker/overlay2/365f99061b8b71aaa6f2b61c1884d0542347695bc311a992035320c3a8652c43/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/app",
                "Destination": "/app",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
        "Config": {
            "Hostname": "65763ad37c38",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "22/tcp": {},
                "8885/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "LANG=C.UTF-8",
                "GPG_KEY=E3FF2839C048B25C084DEBE9B26995E310250568",
                "PYTHON_VERSION=3.9.9",
                "PYTHON_PIP_VERSION=21.2.4",
                "PYTHON_SETUPTOOLS_VERSION=57.5.0",
                "PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/3cb8888cc2869620f57d5d2da64da38f516078c7/public/get-pip.py",
                "PYTHON_GET_PIP_SHA256=c518250e91a70d7b20cceb15272209a4ded2a0c263ae5776f129e0d9b5674309"
            ],
            "Cmd": [
                "/usr/sbin/sshd",
                "-D"
            ],
            "Image": "python-ssh",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {}
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "db19f3f2fa705c5f4fae4ac57b9e9c3db8dd6f3ab5c7e655e3adeb17f9441686",
            "SandboxKey": "/var/run/docker/netns/db19f3f2fa70",
            "Ports": {
                "22/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "2222"
                    },
                    {
                        "HostIp": "::",
                        "HostPort": "2222"
                    }
                ],
                "8885/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "8885"
                    },
                    {
                        "HostIp": "::",
                        "HostPort": "8885"
                    }
                ]
            },
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "97e6d3dc4fb7ec564b4e9cc0e13737754f7c825253ddc8fd188b15389875a01b",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.5",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:05",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "MacAddress": "02:42:ac:11:00:05",
                    "NetworkID": "d1873b5c82ffeba7bd1acbf1088b364a535b67874073faafde3f5d3fa97d9745",
                    "EndpointID": "97e6d3dc4fb7ec564b4e9cc0e13737754f7c825253ddc8fd188b15389875a01b",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.5",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DriverOpts": null,
                    "DNSNames": null
                }
            }
        }
    }
]

进入当前正在运行的容器

方式一:

#我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置

#测试
[root@iZ2ze2kw6hfrrx7qs65neyZ ~]# docker exec -it f5bff212d913 /bin/bash
root@f5bff212d913:/# 

方式二:

[root@iZ2ze2kw6hfrrx7qs65neyZ ~]# docker attach  c808decaed6
docker exec  #进入容器后开启一个新的终端,可以在里面操作

docker attach #进入容器正在执行的终端,不会启动新的进程!

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

#首先进入容器
docker attach 容器id

#在容器里面进行文件的创建
touch test.java

#然后ctrl+Q+P
退出容器

#然后指定容器进行拷贝(无需容器运行,只要容器存在)
docker cp aa66af05c309:/test.java /home

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

学习方式

全部命令敲一遍

小结

作业

作业一:部署Nginx

步骤一:

建议去docker hub上面搜索,可以看到帮助文档等信息镜像仓库

C:\Users\Administrator>docker search Nginx
NAME                                     DESCRIPTION                                      STARS     OFFICIAL
nginx                                    Official build of Nginx.                         20880     [OK]
nginx/nginx-ingress                      NGINX and  NGINX Plus Ingress Controllers fo…   108
nginx/nginx-prometheus-exporter          NGINX Prometheus Exporter for NGINX and NGIN…   51
nginx/unit                               This repository is retired, use the Docker o…   65
nginx/nginx-ingress-operator             NGINX Ingress Operator for NGINX and NGINX P…   2
nginx/nginx-quic-qns                     NGINX QUIC interop                               1
nginx/nginxaas-loadbalancer-kubernetes                                                    1
nginx/unit-preview                       Unit preview features                            0
bitnami/nginx                            Bitnami container image for NGINX                200
ubuntu/nginx                             Nginx, a high-performance reverse proxy & we…   131
bitnamicharts/nginx                      Bitnami Helm chart for NGINX Open Source         1
kasmweb/nginx                            An Nginx image based off nginx:alpine and in…   8
rancher/nginx                                                                             2         0

步骤二:

C:\Users\Administrator>docker pull nginx

                       docker images            #查看容器是否拉取下载成功

步骤三:

docker run -d --name nginx01 -p 3344:80 nginx

docker ps                                      #查看是否运行成功

步骤四:

C:\Users\Administrator>curl localhost:3344  #使用curl的方法
<!DOCTYPE html>
<h1>Welcome to nginx!</h1>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

步骤四:

docker stop nginx01

思考:我们每次改动nginx配置文件,都需要进入容器内部?十分麻烦,我要是可以在容器内部提供一个映射路径,达到在容器外部修改文件内容,容器内部就可以自动修改?-v 数据卷!

作业二:装一个tomcat

#官方的使用
$ docker run -it --rm tomcat:9.0

#我们之前的启动都是后台的,停止了容器之后,容器还是可以查到   docker run -it --rm,一般用来测试,用完删除

#下载之后再启动
docker pull tomcat:9.0

#启动运行
docker run -d -p 3344:8080 --name tomcat01 tomcat:9.0

#进入容器
C:\Users\Administrator>docker exec -it tomcat01 /bin/bash
root@4cb02335354c:/usr/local/tomcat# ls
bin           CONTRIBUTING.md  LICENSE         NOTICE         RUNNING.txt    webapps
BUILDING.txt  filtered-KEYS    logs            README.md      temp           webapps.dist
conf          lib              native-jni-lib  RELEASE-NOTES  upstream-KEYS  work
root@4cb02335354c:/usr/local/tomcat# cd webapps
root@4cb02335354c:/usr/local/tomcat/webapps# ls
root@4cb02335354c:/usr/local/tomcat/webapps#
发现这里的webapps下面是空的,所以我们可以发现:
1.linux命令少了
2.没有webapps。
因为阿里云镜像的原因。默认是最小的镜像,所有不必要的都剔除掉,保证最小的运行环境



#给他添加页面,然后localhost:3344访问
root@4cb02335354c:/usr/local/tomcat# cp -r webapps.dist/* webapps

思考:我们以后要部署项目,如果每次都要进入容器很麻烦,我们可以再容器外部提供一个映射路径,webapps,我们在外部放置项目,就自动同步到内部就好了!

作业三:部署es+kibana

#es 暴露的端口很多!
#es 十分的耗内存
#es 的数据一般需要放置到安全目录!挂载


#启动elasticsearch
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2

#启动了 linux 就卡住了  docker stats 查看 cpu的状态


#es 是十分耗内存的, 1.xG ,   1核2G!

#查看 docker stats

#测试一下es是否成功了

#如果成功了,赶紧关闭tomcat,增加内存的限制
#赶紧关闭,增加内存的限制,修改配置文件 -e 环境配置修改
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e ES_JAVA_OPTS="-Xms64m -Xmx512m" -e "discovery.type=single-node" elasticsearch:7.6.2

#查看cpu状态
docker stats

作业:使用kibana连接es

可视化

  • portainer(先用这个)
docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
  • Rancher(CI/CD再用)

什么是portainer?

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

docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

访问测试:外网:8088端口

刚进去需要设置初始密码:我设置为888888888888

测试的,平时不会用到

Docker镜像

镜像是什么

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

所有的应用,直接打包docker镜像,就可以直接跑起来!

如何得到镜像:

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

Docker镜像加载原理

UnionFS(联合文件系统)

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

UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,他支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem).Union文件系统是Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

Docker镜像加载原理

docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。

bootfs(boot file system)主要包含bootloader和kernel,bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux、Unix系统是一样的,包含boot加载和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载boofs。

黑屏------进入系统(就是一个加载的过程,bootfs去引导加载kernel的过程)

rootfs(root file system),在bootfs之上。包含的就是典型Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。

对于一个精简的OS,rootfs可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs。

分层理解

我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层一层的在下载!

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

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

查看镜像分层的方式可以通过docker image inspect mysql:latest 命令!

C:\Users\Administrator>docker image inspect elasticsearch:7.6.2
[
    {
        "Id": "sha256:f29a1ee41030e3963026369105f3bee76d75fdecbeca07932ac054126be7bff9",
        "RepoTags": [
            "elasticsearch:7.6.2"
        ],
        "RepoDigests": [
            "elasticsearch@sha256:1b09dbd93085a1e7bca34830e77d2981521a7210e11f11eda997add1c12711fa"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2020-03-26T06:39:43.989341611Z",
        "DockerVersion": "19.03.6",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "9200/tcp": {},
                "9300/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/share/elasticsearch/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "ELASTIC_CONTAINER=true"
            ],
            "Cmd": [
                "eswrapper"
            ],
            "Image": "sha256:9e2869a99c9fad439619d3106e68fc6c7a2b5aff34a980e09d7076322df3aaba",
            "Volumes": null,
            "WorkingDir": "/usr/share/elasticsearch",
            "Entrypoint": [
                "/usr/local/bin/docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {
                "org.label-schema.build-date": "2020-03-26T06:34:37.794943Z",
                "org.label-schema.license": "Elastic-License",
                "org.label-schema.name": "Elasticsearch",
                "org.label-schema.schema-version": "1.0",
                "org.label-schema.url": "https://www.elastic.co/products/elasticsearch",
                "org.label-schema.usage": "https://www.elastic.co/guide/en/elasticsearch/reference/index.html",
                "org.label-schema.vcs-ref": "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
                "org.label-schema.vcs-url": "https://github.com/elastic/elasticsearch",
                "org.label-schema.vendor": "Elastic",
                "org.label-schema.version": "7.6.2",
                "org.opencontainers.image.created": "2020-03-26T06:34:37.794943Z",
                "org.opencontainers.image.documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/index.html",
                "org.opencontainers.image.licenses": "Elastic-License",
                "org.opencontainers.image.revision": "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
                "org.opencontainers.image.source": "https://github.com/elastic/elasticsearch",
                "org.opencontainers.image.title": "Elasticsearch",
                "org.opencontainers.image.url": "https://www.elastic.co/products/elasticsearch",
                "org.opencontainers.image.vendor": "Elastic",
                "org.opencontainers.image.version": "7.6.2"
            }
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 790680163,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/93ff2e206626a1e4d935d6224844a8e358df49aff73d0a93550e9231a4a21510/diff:/var/lib/docker/overlay2/07840f497f738654e76207081d86440663e8163748fbd4ae0f9cf8fafff54241/diff:/var/lib/docker/overlay2/767d7e35675dcc98c44e5dbaddbb11d0a1724b6395c4ad9fac82b78b94f78df6/diff:/var/lib/docker/overlay2/3f37ee9b92e93f75ccafc1ce5a0c774618245bcec6e51edf0fa0e0a6f52c7d4c/diff:/var/lib/docker/overlay2/50d6afd08b59ad656d010fbb72c40d8799f80033e76a70985307783ef00cea7c/diff:/var/lib/docker/overlay2/c9a20589c316540f0a09416032a1b19d47d575a8c1b9a3954b01147273eb139e/diff",
                "MergedDir": "/var/lib/docker/overlay2/0f054a783ac64440fd96e189f712106ac77a828e3c8b6b5a21d4b235d9b43b74/merged",
                "UpperDir": "/var/lib/docker/overlay2/0f054a783ac64440fd96e189f712106ac77a828e3c8b6b5a21d4b235d9b43b74/diff",
                "WorkDir": "/var/lib/docker/overlay2/0f054a783ac64440fd96e189f712106ac77a828e3c8b6b5a21d4b235d9b43b74/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:77b174a6a187b610e4699546bd973a8d1e77663796e3724318a2a4b24cb07ea0",
                "sha256:7712f32688d1bef330aa3b4fac2683cec1d7339335ce403483b329423debffb6",
                "sha256:1a090720e70c88e61053c89d3ff01932943b198644f4a7e86426e576b721d2e3",
                "sha256:0535424758bd9ab49a3d03af52a9fa5447b807198fadc35e9f80123a0929402e",
                "sha256:4d2f8f4a58623431cca0ee321bbee273b87070f9e381b3147e4293e83dc146d7",
                "sha256:77c5267605c2c7cf2426242d5df50af78931e66403e9d0d06f2b9fd7adc3adc9",
                "sha256:537370aeea86be07f79bbcd25464a1df23f347bb5313e0ff7ca15d6aad70e074"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

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

举一个简单的例子,加入基于Ubuntu Linux16.04创建一个新的镜像,这就是新镜像的第一层,如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。

该镜像当前已经包含三个镜像层,如图所示。

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

特点

docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!

这一层就是我们通常说的容器层,容器之下的都叫镜像层!

commit镜像

就是把官方镜像运行起来成容器,然后进入容器里面修改,接着退出容器,然后把容器提交成为自己的镜像。

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

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

#这个是直接加载官方的镜像来运行成容器
docker run  -it -p 3344:8080 tomcat

#然后就是在里面进修改(递归拷贝webapps.dist下的所有文件到webapps文件夹下
cp -r webapps.dist/* webapps

#然后就是提交成为新的镜像
docker commit -a="huangmingfeng" -m="add webapps app" 容器id tomcat02:1.0

#确认是否提交成功
docker images

容器数据卷

什么是容器数据卷

docker的理念回顾

将应用和环境打包成一个镜像!

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

MySQL,容器删了,删库跑路!需求:MySQL数据可以存储在本地!

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

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

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

使用数据卷

方式一:直接使用命令来挂载 -v

docker run -it -v C:\Users\Administrator\Desktop\RAG:/home centos:7 /bin/bash

#列出容器信息,查看挂载
C:\Users\Administrator\Desktop\RAG>docker inspect 6a9b750499e3
#查找到Mounts这个key
        "Mounts": [
            {
                "Type": "bind",
                "Source": "C:\\Users\\Administrator\\Desktop\\RAG",
                "Destination": "/home",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],、

就可以实现数据同步,例如我在外面进行创建文件夹kk,里面也有啦

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

实战:安装MySQL

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

#获取镜像
docker pull mysql:5.7

#运行容器,需要做数据挂载!#安装启动mysql,需要配置密码的,这是要注意点!
#官方测试:docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

#启动我们的
-d 后台运行
-p 端口映射
-v 挂载卷
-e 环境配置
--name 启动后容器名
docker run -d -p 3310:3306 -v  C:\Users\Administrator\Desktop\RAG\mysql\conf:/etc/mysql/conf.d -v C:\Users\Administrator\Desktop\RAG\mysql\data:/var/lib/mysql  -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7

C:\Users\Administrator\Desktop\RAG>docker  rm -f c1d18ac0b982
c1d18ac0b982

这样就实现了我们容器数据的持久化功能

具名挂载和匿名挂载

-v 容器内路径!
docker run -d -p --name nginx01 -v /etc/nginx nginx

#查看所有的卷的情况
C:\Users\Administrator\Desktop\RAG>docker volume ls
DRIVER    VOLUME NAME
local     8f9a99bbe430a2a4f7c8eeb9fe4e5b791283bb5fea6f1513414c19509845909b
local     210904267e23b0e42317c3cd65d25ad86c13cf596a90b4fc7bd99d4f39fdfd6f
local     ff58145cd3b55442a315f464333d557b7fa4d14c6ed11a519e56aa0ff1a9a143

#这里发现,这种就是匿名挂载,我们在-v的时候,只写了容器内的路径,没有写容器外的路径

docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx

C:\Users\Administrator\Desktop\RAG>docker volume ls
DRIVER    VOLUME NAME
local     juming-nginx

#通过 -v 卷名:容器内路径
#查看一下这个卷
C:\Users\Administrator\Desktop\RAG>docker volume inspect juming-nginx
[
    {
        "CreatedAt": "2025-07-07T09:25:36Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data",
        "Name": "juming-nginx",
        "Options": null,
        "Scope": "local"
    }
]

这里可以在docker 的工作目录下找到所有的容器信息,以及挂载信息

我们通过具名挂载,可以方便的找到我们的卷,大多数情况在使用的是“具名挂载”

如何确定是具名还是匿名,还是指定路径挂载

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

拓展:

#ro readonly 只读
#rw readwrite 可读可写

#一旦设置了容器权限,容器对我们挂载出来的内容就有限定了!
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx

#ro 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作的!

初识DockerFile

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

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

#创建一个dockerfile文件,名字可以随机,建议Dockerfile
#文件中的内容 指令(大写) 参数
FROM centos

VOLUME ["volume01","volume02"]

CMD echo "------end------"
CMD /bin/bash

#这里的每一个命令,就是镜像的一层
[root@iZ2ze2kw6hfrrx7qs65neyZ docker-test-volume]# vim dockerfile1
[root@iZ2ze2kw6hfrrx7qs65neyZ docker-test-volume]# cat dockerfile1

#这里要注意,镜像名字前面不可以有/
[ docker-test-volume]# docker build -f dockerfile1 -t kuangshen/centos . 

[root@iZ2ze2kw6hfrrx7qs65neyZ docker-test-volume]# docker run -it kuangshen/centos
[root@4c4c6a7195d7 /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  volume01  volume02
[root@4c4c6a7195d7 /]# ls -l
total 56
lrwxrwxrwx   1 root root    7 Nov  3  2020 bin -> usr/bin
drwxrwxrwt   7 root root 4096 Sep 15  2021 tmp
drwxr-xr-x  12 root root 4096 Sep 15  2021 usr
drwxr-xr-x  20 root root 4096 Sep 15  2021 var
drwxr-xr-x   2 root root 4096 Jul  7 11:22 volume01
drwxr-xr-x   2 root root 4096 Jul  7 11:22 volume02

这里可以发现这两个目录都挂载出来了。(这个是匿名挂载)

这里可以通过 docker inspect 4c4c6a7195d7后找到里面的mounts可以看看挂载到哪里了。

这种方式我们使用的非常多,因为我们通常会构建自己的镜像!

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

数据卷容器

多个mysql同步数据!

#启动3个容器,通过自己写的镜像启动

docker run -it --name docker02 --volumes-from docker01 kuangshen/centos
docker run --name docker03 --volume-from docker01 kuangshen/centos
# 测试,可以删除docker01,查看一下docker02和docker03是否还可以访问这个文件
# 测试依旧可以访问

只要或者就能够拷贝

多个mysql实现数据共享

C:\Users\Administrator\Desktop\RAG>docker run -d -p 3310:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
73fdec30005815185ca78a39233319adb207a762dc4b89b30340f19700d40a0a

C:\Users\Administrator\Desktop\RAG>docker run -d -p 3311:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7
f8660b34eb1ba0fc6c9bff7e5d0b81d34b4b2c739bf841afe30a8e8af7d0c77b

结论:

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

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

DockerFile

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

构建步骤:

1.编写一个dockerfile文件

2.docker build构建成为一个镜像

3.docker run 运行镜像

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

DockerFile构建过程

基础知识:

1.每个保留关键字(指令)都是必须是大写字母

2.执行从上到下顺序执行

3.#表示注释

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

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

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

步骤:开发,部署,运维。。。缺一不可

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

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

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

DockerFile的指令

以前的话我们就是使用别人的,现在我们知道了这些指令后,我们来练习自己写一个镜像!

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

实战测试

Docker Hub中99%都是从这个基础镜像过来的FROM scratch,然后配置需要的软件和配置来进行构建。

创建一个自己的centos

# 1. 编写Dockerfile的文件
FROM centos
MAINTAINER MINGFENG<2856055319@qq.com>

ENV MYPATH /user/local
WORKDIR $MYPATH


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

EXPOSE 80

CMD echo $MYPATH
CMD echo "-------end-------"
CMD /bin/bash

#2.通过这个文件构建自己的镜像
# 命令 docker build -f mydockerfile(文件路径) -t 镜像名:[TAG] .

#测试
docker build -f mydockerfile -t mycentos:0.1 .

Successfully build e2bd75cfe070
Successfully tagged mycentos:0.1

#测试运行一下

对比:之前的原生的centos

我们增加之后的镜像,会发现工作目录变成/usr/local ,以及多了很多命令例如vim

可以使用docker history 容器id

这个命令可以查看任何一个容器的dockerfile,

我们平时拿到一个镜像,可以研究一下它是怎么做的了

CMD ENTRYPOINT区别

#1编写dockerfile文件
[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# vim dockerfile-cmd-test
FROM centos
CMD ["ls","-a"]

#2构建镜像
[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# docker build -f dockerfile-cmd-test -t cmdtest .

#3run运行,发现我们的ls -a命令生效
[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# docker run cmdtest
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

#想追加一个命令 -l  ls -al
[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# docker run cmdtest -l
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "-l": executable file not found in $PATH: unknown.

#cmd的清理下 -l 替换了CMD ["ls","-a"]命令,-l不是命令所以报错!
[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# vim dockerfile-entrypoint-test
FROM centos
ENTRYPOINT ["ls","-a"]
[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# docker build -f dockerfile-entrypoint-test -t entrypoint-test .

[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# docker run entrypoint-test
.
..
.dockerenv
bin
dev
etc
#这里我们命令行追加的命令是直接拼接在我们的ENTRYPOINT命令的后面的
[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# docker run entrypoint-test -l
total 56
drwxr-xr-x   1 root root 4096 Jul  8 02:02 .
drwxr-xr-x   1 root root 4096 Jul  8 02:02 ..
-rwxr-xr-x   1 root root    0 Jul  8 02:02 .dockerenv
lrwxrwxrwx   1 root root    7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x   5 root root  340 Jul  8 02:02 dev
drwxr-xr-x   1 root root 4096 Jul  8 02:02 etc

实战:tomcat镜像

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

2.编写dockerfile文件,官方命名Dockerfile,build会自动寻找这个文件,就不需要-f指定了!

FROM centos
MAINTAINER kuangshen<2856055319@qq.com>

COPY readme.txt /usr/local/readme.txt

ADD jdk-8ull-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.22.tar.gz /usr/local/

RUN yum -y install vim

ENV MYPATH /usr/local
WORKDIR $MYPATH

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

EXPOSE 8080

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

3.构建镜像

#docker build -t diytomcat .

4.启动镜像成容器

docker run -d -p 9090:8080 --name kuangshentomcat -v /home/kuangshen/build/tomcat/test: /url/local/apache-tomcat-9.0.22/webapps/test -v/home/kuangshen/build/tomcat/tomcatlogs/:/url/local/apache-tomcat-9.0.22/logs diytomcat

5.访问测试

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

<?xml version="1.0" encoding="UTF-8"?>  
<web-app version="2.4" 
    xmlns="http://java.sun.com/xml/ns/j2ee"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee  
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">  
</web-app>

还需要在webapp里面做一个index.jsp文件

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

发布自己的镜像

DockerHub

1.地址 https://hub.docker.com/注册自己的账号

2.确定这个账号可以登录

3.在我们服务器上提交自己的镜像

docker login -u xxx -p xxx

4.登录完毕之后,就可以开始提交镜像了

docker push 镜像Name:[tag]

#push镜像的问题?
The push refers to repository [docker.io/kuangshen/diytomcat2]
An image does not exist locally with the tag:kuangshen/diytomcat2

#解决这个问题,添加一个tag
docker tag 镜像id 新镜像name:tag

提交的时候也是按照镜像的层级来进行提交的。

阿里云镜像服务上

1.登录阿里云

2.找到容器镜像服务

3.创建命名空间

4.创建镜像仓库

5.浏览仓库信息,跟着步骤就可以上传镜像了

Docker所有流程小结

Docker网络原理

理解Docker网络

测试

三个网络

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

#下面这个是没有任何的容器在运行的时候,就是只有docker01一个网卡
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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:16:3e:0a:7f:3a brd ff:ff:ff:ff:ff:ff
    inet 10.70.141.25/16 brd 10.70.255.255 scope global dynamic eth0
       valid_lft 291179128sec preferred_lft 291179128sec
    inet6 fe80::216:3eff:fe0a:7f3a/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:a1:30:38:4f brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:a1ff:fe30:384f/64 scope link 

#这里是启动一个tomcat01容器,然后查看网卡信息
docker run -d -P --name tomcat01 tomcat ip addr

这里可以发现就多了一个
126: veth1a417e9@if125: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 9e:a2:f0:c7:5c:2f brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::9ca2:f0ff:fec7:5c2f/64 scope link 
       valid_lft forever preferred_lft forever

#如果再启动一个tomcat容器,就会发现又多一个网卡信息
docker run -d -P --name tomcat02 tomcat ip addr

128: veth95a7a7f@if127: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether c6:ec:72:c2:ab:20 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::c4ec:72ff:fec2:ab20/64 scope link 
       valid_lft forever preferred_lft forever

#进入容器,并且使用apt-get先安装一下ip命令
docker exec -it tomcat01 /bin/bash
apt-get update && apt-get install -y iproute2

#查看容器的内部网络地址 ip addr,发现容器启动的时候会得到一个eth0@if262 ip地址,docker分配的!
root@f82b93f6a457:/usr/local/tomcat# 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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
125: eth0@if126: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever


如果再启动一个容器就是
172.17.0.3


#思考:linux能不能ping通容器内部!
[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# 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.053 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.058 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.057 ms

#linux 可以ping通docker容器内部!

原理

1.我们每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要安装了docker,就会有一个网卡docker0

桥接模式,使用的技术是evth-pair技术!

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

evth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一段连着协议,一段彼此相连

正因为有这个特性,evth-pair充当一个桥梁,连接各种虚拟网络设备的

openStac,Docker容器之间的连接,OVS的连接,都是使用evth-pair技术

2.我们来测试一下tomcat01 和tomcat02 是否能够ping通

docker exec -it tomcat02 ping 172.17.02

#结论:容器和容器之间可以互相ping通的!

绘制一个网络模型图

结论:tomcat01和tomcat02是公用的一个路由器,docker02

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

小结

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

Docker中的所有网络接口都是虚拟的,虚拟的转发效率高!(内网传递文件!)只要容器删除,对应的网桥(一对网卡)就没有了。

高可用!

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

docker network ls

docker network inspect bridge网卡的id

--link

给tomcat02安装ping命令
root@aad4bfe13583:/usr/local/tomcat# apt-get install -y iputils-ping


然后在linux上面使用精简命令使得tomcat02 ping tomcat01 这里我们发现了根本就ping不通
[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known

#通过--link就可以解决网络连通问题
docker run -d -P --name tomcat03 --link tomcat02 tomcat
docker exec -it tomcat 03 ping tomcat02
会发现这里可以ping通

#反向可以ping通吗?(就是tomcat02 ping tomcat03)会发现行不通。

探究:inspect!(这里是使用的docker network inspect 网卡bridge的id)

其实这个tomcat03就是在本地配置了tomcat02的配置?

docker exec -it tomcat02 cat /etc/hosts

--link 就是我们在hosts配置中增加了一个172.17.0.3 tomcat02 aad4bfe13583

我们现在玩Docker已经不建议使用--link了!

自定义网络,不适用docker0!

docker0问题:他不支持容器名连接访问!

自定义网络

查看所有的docker网络

[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
cdfb53d37ca4   bridge    bridge    local
0ab7551a3614   host      host      local
8494dc1c6d7b   my_net    bridge    local
6969a1201ceb   none      null      local

网络模式

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

none :不配置网络

host :和宿主机共享网络

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

测试

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

#docker0特点,默认,域名不能访问,--link可以打通连接!

#我们可以自定义一个网络!
# --driver bridge  网络模式
# --subnet 192.168.0.0/16 子网
# gateway 192.168.0.1 网关
命令如下
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
da9fe65aa180c62f53c7892c51c3f2b43c2b1138b9aa75451474078acf9e837e
docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
cdfb53d37ca4   bridge    bridge    local
0ab7551a3614   host      host      local
da9fe65aa180   mynet     bridge    local
6969a1201ceb   none      null      local


#自定义成功之后,就可以查看细节了
docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "da9fe65aa180c62f53c7892c51c3f2b43c2b1138b9aa75451474078acf9e837e",
        "Created": "2025-07-08T15:48:51.520985696+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.0.0/16",
                    "Gateway": "192.168.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

这里我们的服务就以及创建好了,那我们的服务就都可以放在我们的网络服务里面了,下面我们就创建服务放在这个网络里面,然后进行通过这个容器名字互ping,发现可以正常互ping

[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# docker run -d -P --name tomcat-net-01 --net mynet mytomcat
8053a8cd5a036166c0c235e8d70979e395cf2aff04db9c428056426622110cab
[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# docker run -d -P --name tomcat-net-02 --net mynet mytomcat
51692baefb409c1c7b3a3ec7f596b1946d803dcc221b8aa28514e1d8754869dc
[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# 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.091 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.131 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.079 ms

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

好处:

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

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

网络连通

测试打通tomcat01 - mynet

#连通之后就是将tomcat01 直接加入到mynet网络下

#一个容器两个ip地址 阿里云服务:公网ip 私网ip

 docker network connect mynet tomcat01
 docker network inspect mynet
[
            "e3c51f093fc81baf919d2bc760c2d82eeec2117ae894e23d7a91a2b0d8fc6d6c": {
                "Name": "tomcat01",
                "EndpointID": "8379f3ec6b7572c414918ac4cd47819f06e4c99b83ec5e2b0a3c306b84790c52",
                "MacAddress": "02:42:c0:a8:00:04",
                "IPv4Address": "192.168.0.4/16",
                "IPv6Address": ""
            }
        
        "Options": {},
        "Labels": {}
    }
]
#01 连接ok
[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# 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.109 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.071 ms

#02 依旧是不能够连通的
[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# docker exec -it tomcat02 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known

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

实战:部署Redis集群

[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# docker network create redis --subnet 172.38.0.0/16
ba28c459831db7850380e8f6e6911eb5348cebed8744d667b177d22032fa466b
[root@iZ2ze2kw6hfrrx7qs65neyZ dockerfile]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
cdfb53d37ca4   bridge    bridge    local
0ab7551a3614   host      host      local
da9fe65aa180   mynet     bridge    local
6969a1201ceb   none      null      local
ba28c459831d   redis     bridge    local

Idea整合Docker

Docker Compose

Docker Swarm (K8s)

CI/CD Jenkins

### DeepSeek 配置教程完整指南 #### 一、环境准备 为了功配置和运行 DeepSeek,需满足一定的硬件条件。最低配置应具备 CPU(支持 AVX2 指令集)、16GB 内存以及至少 30GB 的存储空间;而推荐配置则建议采用 NVIDIA GPU(如 RTX 3090 或更高级别),搭配 32GB 内存及不少于 50GB 存储容量[^3]。 对于操作系统的选择上,DeepSeek 支持 Windows、macOS 和 Linux 平台。此外,在某些特定功能模块的使用过程中可能还会涉及到 Docker 的应用,因此提前确认是否已安装好相应的工具链也是必要的准备工作之一。 #### 二、获取源码与初始化工作区 通过 Git 命令行工具来下载官方发布的最新版本代码库: ```bash git clone https://github.com/deepseek/deepseek.git cd deepseek ``` 上述命令会将整个项目复制到当前目录下的 `deepseek` 文件夹内,并切换至该文件夹继续后续操作[^1]。 #### 三、设置 Python 虚拟环境 为了避免与其他项目的依赖冲突,强烈建议为本项目单独建立一个新的虚拟环境。这里以创建名为 `deepseek_env` 的 Python 3.x 版本为例展示具体做法: ```bash virtualenv -p python3 deepseek_env source deepseek_env/bin/activate ``` 完这一步骤之后即可进入下一步——安装所需的第三方包和其他资源文件[^2]。 #### 四、安装所需组件 确保所有必需项都已被正确载进来非常重要。通常情况下,除了基础的语言解释器外还需要额外引入一些专门用于处理深度学习任务的支持类库。这部分可以通过 pip 来实现自动化管理: ```bash pip install -r requirements.txt ``` 此过程将会读取根目录下预先定义好的 `requirements.txt` 清单文档,从而自动拉取并安装每一个条目所对应的软件包及其版本号信息。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值