Docker基础入门详解

Posted 敲代码的小小酥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker基础入门详解相关的知识,希望对你有一定的参考价值。

一、产生背景

在传统软件开发流程中,研发程序员将功能代码研发完成后,交由测试人员进行测试,最后通过运维人员部署上线。但是在这个过程中,常常因为环境问题、配置问题、软件版本问题等等诸多因素,造成一些问题。Docker技术的出现就是为了解决因部署实施而带来的一系列问题。

Docker技术实现了将开发环境、相关软件、配套环境等一系列研发环境打包成镜像文件,交由测试人员、运维人员使用。这样就减少了因部署而带来的一系列扯皮问题。除此之外,Docker提供了很多现成镜像,可以由用户直接使用,减少了一些中间件的安装。

总之,Docker方便了软件的安装部署,实现了一个镜像,多处复用的效果。

个人理解:
在固定服务器,固定服务的场景下,不需要使用Docker技术。因为开发环境,测试环境,上线环境,都是固定不变的。不管是开发,测试还是运维,都是基于固定的环境和软件开展工作的。
而对于一个服务,多处部署的应用场景,比较适合使用Docker技术。例如互联网大厂中,一个产品项目可能需要往全国甚至全世界多个机房中心中部署,那么这种场景就比较适合使用Docker技术。

二、什么是Docker

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows操作系统的机器上,也可以实现虚拟化。

虚拟化容器:
Docker采用虚拟化容器技术,虚拟化容器是在操作系统层面实现虚拟化,直接复用本地主机的操作系统,而虚拟化出容器所需的资源。虚拟化出来的容器是容器所具备功能所需的最小资源,没用的功能和组件,不会出现在容器中。所以Docker容器具有体积小的特性。这也是为何Docker容器中输入很多linux命令不识别的原因。因为没用的组件和功能,容器中默认是不携带的。

虚拟化容器与虚拟机比较:
传统虚拟机技术是在硬件层面实现的虚拟化技术,它将虚拟化出来一套完整的操作系统。而Docker容器是在本地主机操作系统基础上,虚拟化出来所需功能组件的最小容器。因此,传统虚拟机技术所产生的镜像比Docker容器的镜像更大,更笨重。

三、Docker基本组成

前提条件

Docker要求运行在linux系统上,linux系统内核要求在3.8以上。在Centos系统上,要求centos7以上,64位操作系统。现在衍生出了Windows版本,其本质还是使用linux系统内核,只不过在Windows系统上模拟出了linux系统内核。

Docker由镜像、容器和仓库组成:

镜像

这里的镜像,和传统虚拟机中的.iso镜像,有异曲同工之处。传统虚拟机中的.iso镜像文件放在虚拟机中,可以创建出操作系统实例来。在Docker中的镜像,可以创建出Docker容器实例。上面说过,Docker容器并不是整个操作系统,而是所需功能的最小容器。
镜像就是一个模板,可以创建出很多容器实例。

容器

Docker镜像启动起来的每一个实例,都称之为容器。例如,redis镜像启动的容器,就是redis服务。mysql镜像启动的容器,就是mysql服务等。

仓库

存放镜像的地方,就是Docker的仓库。其机制类似于Maven仓库或git仓库。只不过存放的是Docker镜像。分为本地仓库和远程仓库。本地仓库就是宿主机本地存放镜像的地方。本地仓库没有的镜像,可以从远程仓库拉取。远程仓库分为公共远程仓库和私有远程仓库。公共远程仓库有Docker Hub或阿里云仓库。私有远程仓库就是公司 内部自己搭建的Docker仓库。私有远程仓库可安装Docker registry软件进行搭建。具体操作这里不再记录。Docker仓库运行流程如下:

我们自定义的镜像,也可以上传到远程仓库,供别人拉取使用。阿里云仓库是付费的。
甜点: 在个人安装Docker的宿主机上,可配置阿里云提速器,来加快镜像的远程拉取速度。这里注意要区分与配置阿里云远程仓库地址。配置阿里云远程仓库地址可以用来加快拉取速度,因为Docker Hub是国外网站,拉取速度较慢。而这里 说的配置阿里云提速器,是在配置了阿里云仓库后,更进一步的提速效果。具体的配置方式是登陆自己的阿里云账号,然后搜索容器镜像服务,然后点击此选项,然后选择镜像提速器菜单,安装上面操作配置即可,如下图所示:

可以看出这是跟个人账号挂钩的一个操作,在个人学习时,可以配置使用。

四、Docker基本操作命令大全

系统级别命令

镜像相关命令

  1. 查看本地仓库镜像:
docker images

输出字段及含义如下图:


其中一个镜像可以有多个TAG版本存在。使用某个版本,可以通过镜像名称:TAG来指定。当版本为latest时,可以省略:TAG。否则必须使用镜像名称:TAG

  1. 查询远程仓库镜像:
docker search xxx

可以列出镜像,如下图所示:

其中OFFICAL代表是否官方。优先选择官方镜像进行拉取。这里只是搜索镜像,并不包含具体版本号,一般镜像包含了各个版本。我们可以直接在镜像名后面加我们想要的版本即可。如果不加版本,默认拉取latest版本。
在Docker Hub官网,也可以搜索某个镜像。

  1. 拉取镜像到本地:
docker pull 镜像名字[:TAG]

如果不加TAG,默认拉取最新的。

  1. 删除镜像:
docker -rmi 镜像名字ID

镜像启动的所有实例必须停止运行才可以删除镜像。

容器相关命令

  1. 启动容器命令:
docker run

参数:

--name xxx   #指定容器名称为xxx
-d #后台运行,并返回容器ID,此方式开启容器后不进入容器
-it #其实是-i和-t两个参数,一般都在一起使用,开启交互式容器,启动容器后进入容器内部
-p 宿主机port:容器port  #指定宿主机端口与容器端口对应关系。可在宿主机上通过此端口访问容器服务
-v 宿主机路径:容器内部路径  #将容器内部某个路径挂载到宿主机上,实现数据的同步和持久化
  • 后台启动容器命令:
 docker run -d -p 1000:1000 --name 容器名称 镜像ID(镜像名称:TAG)
  • 交互启动容器命令:
docker run -it -p 1000:1000 --name 容器名称 镜像ID(镜像名称:TAG) /bin/bash

在交互式容器启动时,需要在命令后面加上/bin/bash或bash命令,这样才能进入容器内部,与容器内部进行交互。这点需要特别注意。

退出容器:
交互式进入容器后,如果退出容器到宿主机呢?两种方式:
ctrl+D或exit命令退出容器,容器也会停止。
ctrl+p+q退出容器,容器不会 停止。

文件挂载:
在容器中的数据,会随着容器的删除而删除,而且容器中配置文件的修改,需要先进入容器才能修改。使用文件挂载参数-v,将容器内文件与宿主机文件进行映射后,容器内文件和宿主机映射文件就会保持同步,在宿主机修改配置文件,容器内 对应配置文件也会修改(容器重启后生效)。在容器内产生的数据,在宿主机映射文件也会产生相应数据。
例如在redis容器或mysql容器中,都需要将配置文件和数据文件进行挂载,一个是便于配置文件的修改,一个是对redis日志或mysql数据进行持久化保持。
挂载命令:

docker run -d --priviledge=true -v 宿主机绝对路径:容器绝对路径 镜像名

其中--priviledge=true是授权参数,最好 加上,否则有时会出问题。
2. 查看容器实例命令:
查询正在运行的容器实例:

docker ps

查看正在运行和已经停止的容器实例:

docker ps -a

这里需要注意,当用某个镜像启动容器后,容器就会在宿主机存在。即使这个实例停止运行了,那么这个容器还是存在的,我们可以继续启动这个容器。

  • 启动某个容器命令:
docker start 容器ID

关闭某个容器命令:

docker stop 容器ID

删除容器命令:

docker rm 容器ID

删除容器后,容器才会在宿主机消失。删除容器是rm,删除镜像是rmi,其中这个i就代表image镜像的意思。

  1. 进入某个容器命令
    上面讲到启动一个后台运行的容器,那么如果 想进入这个容器做交互,应该如何进去呢?执行以下命令:
docker exec -it 容器ID  /bin/bash

退出按ctrl+D退出即可,因为是后台运行启动的,这样退出也不会停止容器运行。

还有一个进入容器内部的命令:

docker attach 容器ID

这种方式很少用,原因如下:

3. 查看容器详情命令:

docker inspect 容器ID

返回json格式容器详情信息,内容很多,如下所示:

[
    
        "Id": "3d25328ac0bbab7525caadf322e1df54ef6ca776f258f6c415f6019d1514824f",
        "Created": "2022-08-28T06:55:02.245198929Z",
        "Path": "docker-entrypoint.sh",
        "Args": [
            "redis-server"
        ],
        "State": 
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 21683,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2022-08-28T06:55:04.16474428Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        ,
        "Image": "sha256:3edbb69f9a493835e66a0f0138bed01075d8f4c2697baedd29111d667e1992b4",
        "ResolvConfPath": "/var/lib/docker/containers/3d25328ac0bbab7525caadf322e1df54ef6ca776f258f6c415f6019d1514824f/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/3d25328ac0bbab7525caadf322e1df54ef6ca776f258f6c415f6019d1514824f/hostname",
        "HostsPath": "/var/lib/docker/containers/3d25328ac0bbab7525caadf322e1df54ef6ca776f258f6c415f6019d1514824f/hosts",
        "LogPath": "/var/lib/docker/containers/3d25328ac0bbab7525caadf322e1df54ef6ca776f258f6c415f6019d1514824f/3d25328ac0bbab7525caadf322e1df54ef6ca776f258f6c415f6019d1514824f-json.log",
        "Name": "/keen_noether",
        "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/ef1cb55fe9ba3130296f2cecc676be442e78e76524b2b58a1ba0ef58aac39879-init/diff:/var/lib/docker/overlay2/8c626981a567a606070bdc8e00a103eed11d0859dcfce2763b37a4f2e257b668/diff:/var/lib/docker/overlay2/c19216a0ddf38928401b118816cda02bd497603ec3109647bd147eabef3c2dd8/diff:/var/lib/docker/overlay2/2d98fdbbe975db2295a238830f740242863eb62834e1c1288e9096f88aea17b6/diff:/var/lib/docker/overlay2/df05555cfad1eec6219f2cb14ec183be109d09f04a4a245dd755b619551492b8/diff:/var/lib/docker/overlay2/40df4c9e096704ba37d1e916faf0f02a012bd061b6883de5a3c12699b2f30e41/diff:/var/lib/docker/overlay2/f12fbd3a76a4f40e20699b214a894a19c32d6650b3824ed7fb7f47876531866d/diff",
                "MergedDir": "/var/lib/docker/overlay2/ef1cb55fe9ba3130296f2cecc676be442e78e76524b2b58a1ba0ef58aac39879/merged",
                "UpperDir": "/var/lib/docker/overlay2/ef1cb55fe9ba3130296f2cecc676be442e78e76524b2b58a1ba0ef58aac39879/diff",
                "WorkDir": "/var/lib/docker/overlay2/ef1cb55fe9ba3130296f2cecc676be442e78e76524b2b58a1ba0ef58aac39879/work"
            ,
            "Name": "overlay2"
        ,
        "Mounts": [
            
                "Type": "volume",
                "Name": "9bd2c45c0f4711a8291c6eb4a2607aa20f9e23b402facef0be854925dfbba76f",
                "Source": "/var/lib/docker/volumes/9bd2c45c0f4711a8291c6eb4a2607aa20f9e23b402facef0be854925dfbba76f/_data",
                "Destination": "/data",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            
        ],
        "Config": 
            "Hostname": "3d25328ac0bb",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": 
                "6379/tcp": 
            ,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "GOSU_VERSION=1.14",
                "REDIS_VERSION=7.0.4",
                "REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-7.0.4.tar.gz",
                "REDIS_DOWNLOAD_SHA=f0e65fda74c44a3dd4fa9d512d4d4d833dd0939c934e946a5c622a630d057f2f"
            ],
            "Cmd": [
                "redis-server"
            ],
            "Image": "redis",
            "Volumes": 
                "/data": 
            ,
            "WorkingDir": "/data",
            "Entrypoint": [
                "docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": 
        ,
        "NetworkSettings": 
            "Bridge": "",
            "SandboxID": "adfae3e2a0fae1e742453439bfe09024f92eb951b72eb4e363b965ff913c9c75",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": 
                "6379/tcp": null
            ,
            "SandboxKey": "/var/run/docker/netns/adfae3e2a0fa",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "2a3d532504abe9f43339fb9cd9e8021a726641819e7ce25e7c0ac4148a6bb925",
            "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": "7667f6780a0f4b166b8487b3eca53cd6754fb92d16d599283ca3129f35c3a808",
                    "EndpointID": "2a3d532504abe9f43339fb9cd9e8021a726641819e7ce25e7c0ac4148a6bb925",
                    "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
                
            
        
    
]


其中包含了容器的网络模式,ip,镜像,状态,挂载情况(Mounts)等等信息。总之容器的全部信息都可以在这里找到。
4. 其他容器命令

  • 查看容器日志命令:
docker  logs  容器ID

此命令在后台运行容器时使用,可以查看容器内服务运行日志。特别是容器运行失败或容器内服务出现问题时,可以通过该命令快速浏览容器软件所产生的日志。

查看容器内部进程:

docker top 容器ID

复制容器内文件到宿主机:

docker cp 容器ID:容器内文件路径   宿主机存放文件路径

五、Dockerfile

什么是Dockerfile

上面我们讲到可以从远程仓库拉取现成的Docker镜像。那我们该如何制作自己的镜像呢?比如我们的项目打成jar包,在jdk里运行,想要把jdk环境和jar包制作成一个镜像,供其他人通过Docker进行运行,该如何做呢?这就用到了Dockerfile技术。

Dockerfile是构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。

Dockerfile就是基于某个基础镜像,对镜像的一个增强脚本。比如,基于centos镜像,要安装jdk8环境,并且要运行我们项目的jar包。或者往centos镜像中添加ifconfig命令的功能,或者vim命令的功能。这都算是对基础镜像的一个增强。通过编写Dockerfile脚本文件,构建出一个新的镜像,包含上述的增强功能。

构建Dockerfile三步曲

  • 编写Dockerfile文件
  • 使用Dockerfile文件构建镜像
  • 运行生成的镜像容器

如下图所示:

Dockerfile语法指令

上面提到Dockerfile是一个脚本文件,用来构建镜像增强。docker定义了Dockerfile的一些关键字指令(保留字指令)。这些指令特性如下:

下面看都有哪些指令:

  • FROM:
    指定加强镜像是基于哪个镜像做加强的。写在Dockerfile第一行。基于哪个镜像,用镜像名称:TAG表示即可。
  • MAINTAINER:
    Dockerfile作者和邮箱地址,可选项
  • RUN:
    用Dockerfile文件构建镜像时执行的命令,支持shell格式和exec格式两种。一般使用shell命令。在docker build构建镜像时执行RUN 后面定义的shell命令。
  • EXPOSE:
    容器服务对外暴露的端口。如tomcat镜像暴露8080端口,就是容器中tomcat暴露的端口。
  • WORKID:
    指定交互式进入容器后默认到达的目录,一个落脚点。
  • USER:
    指定镜像以什么用户来执行,如果不指定,默认是root用户。
  • ENV:
    用来构建镜像过程中设置环境变量。以k v形式定义。例如: ENV MYPATH /usr/local/tomcat表示设置MYPATH环境变量为/usr/local/tomcat。在Dockerfile中,就可以使用$MYPATH来代表这个路径。
  • VOLUME:
    容器数据卷,用于保存和持久化工作。等同于docker run -v 参数,在这里定义后无需在容器启动时指定了。
  • ADD:
    将宿主机文件拷贝到容器中,并解压。即宿主机中压缩文件拷贝到容器后,会自动解压出来。默认拷贝Dockerfile同级目录下的文件。所以要将Dockerfile文件和要拷贝进容器的文件放在同一个目录下。
  • COPY:
    类似于ADD命令,只不过没有自动解压功能。一般使用ADD命令。
  • CMD:
    定义在容器启动后,执行的命令。也是支持shell格式和exec格式。
    CMD [“可执行文件”,“参数1”,“参数2”…] 在容器启动后,执行shell命令,一般用于启动容器中的服务。例如tomcat容器中定义CMD命令,就是在tomcat容器启动后,执行CMD后面的命令,启动tomcat服务。
    Dockerfile文件中可以定义多个CMD命令,但只有最后一个生效。CMD会被docker run后面的参数替换。替换是当docker run后面的参数与CMD指令的作用相冲突时,以指令参数为准。当作用不冲突时,是叠加效果。

需要注意的是,RUN指令后面的shell脚本是构建镜像时执行的命令,CMD指令是容器启动后执行的命令。

  • ENTRYPOINT:
    也是在容器启动时执行命令,类似于CMD。与CMD的区别是ENTRYPOINT不会被docker run后面的命令所覆盖(不理解这句话含义)。命令格式: ENTRYPOINT [“可执行文件”,“参数1”,“参数2”]。


ENTRYPOINT 作为启动容器的运行命令时,CMD命令就不再是运行命令了,而是ENTRYPOINT的一个参数。如上图例子,衍生出来的命令其实就是 nginx -c /etc/nginx/nginx.conf。其中nginx -c 是ENTRYPOINT命令,其是不会被用户后续追加命令覆盖的,后面的/etc/nginx/nginx.conf是CMD命令,其不再是运行命令,而是参数命令。而且它也保留CMD特性,会被后面的CMD命令所覆盖。如用户自定义了 -c /etc/nginx/new.conf后就将之前CMD命令覆盖了。

tomcat Dockerfile文件查看

在Docker Hub上搜索tomcat镜像,并选择第一个搜索结果(官方镜像),点进去后,选择自己想要查看的版本,如下图所示:


这里看Dockerfile脚本文件的最后两行:

可以看到,tomcat容器暴露出来端口是8080,且容器启动后,执行catalina.sh命令。这就是启动tomcat服务的命令。所以启动tomcat镜像后,tomcat也就自动启动了。

注意:
当以交互式启动tomcat镜像时,不要加/bin/bash命令,因为这样会覆盖掉最后的CMD命令。这样就不会执行tomcat启动命令。这样容器 虽然启动了,但是tomcat没有运行。所以遇到这种情况时,就不要以交互式方式启动了,先以后台方式启动,然后再进入容器内部。

Dockerfile构建镜像

命令:

docker build -t 新镜像名字:TAG

构建好的镜像自动进入docker本地镜像仓库,并不会生成具体某个可看见的文件。其中TAG版本号自己定义即可。定义好容器后启动容器即可。

Docker执行Dockerfile的大致流程如下:

  1. docker从基础镜像运行一个容器
  2. 执行每一个指令对基础镜像进行修改
  3. 执行类似docker commit命令提交一个新的镜像层
  4. docker再基于新镜像运行一个新容器
  5. 执行Dockerfile下一条指令直至执行完毕。

虚悬镜像

在使用Dockerfile构建镜像时,有时会出现虚悬镜像。所谓虚悬镜像就是镜像名称和TAG都是none的镜像。虚悬镜像产生的原因可能是Dockerfile在一层一层的生成新的镜像时,所产生的垃圾镜像,没有用,直接删掉即可。

六、网络模式

查看网络模式命令:

docker network ls

docker默认网络模式有如下三种:

bridge桥接模式

桥接模式是最常用的模式,也是默认模式。Docker服务会默认创建一个docker0网桥,如下图所示:

这样,每一个容器都会有自己的一个ip,ip网段和docker0的网段一样。这样就可以实现容器之间,容器与宿主机之间的通信。如下图所示:

其中,docker0是网桥,起到交换机的作用。网桥ip一般为172.17.0.1。容器ip为172.17.0.2等等。需要注意的是,容器每次重启后,ip都不是固定的,是随机变化的。

Host模式

想使用Host模式,在docker run命令后加参数–network host或-net host即可。使用host模式,容器ip和端口用宿主机ip和端口就行。Host模式容器详情中网络模式如下:

自定义网络模式

docker支持自定义网络模式。我们除了上述几种网络模式外,我们可以自定义网络模式,命令如下:

docker network create 网络名称

自定义创建的网络模式,本质还是用桥接模式。只不过网络名称是自己定义的。那么自定义网络模式有何作用呢?
自定义网络模式是为了解决容器每次启动后,ip都会变化造成的问题。例如我们在连接数据库,redis时,配置文件写ip地址进行连接。当容器重启后,ip变了。那么数据库就连接不上了。
容器使用自定义网络后,就可以通过容器名称进行容器的连接了。当连接mysql容器,redis容器的服务与mysql容器、redis容器都在同一个自定义网络时,就可以通过写容器 名称来代替ip地址,进行mysql和redis的连接。这样就规避了ip变化带来的问题。
需要注意的是,所有的容器必须都在一个自定义网络中,且启动容器时必须通过 --name指定容器名称。如果不指定名称,docker自动生成的名称也不能通过容器名称访问。虽然自定义网络也是桥接模式,但是使用默认的桥接模式是不能通过容器名访问的。

七、Dockerfile创建jar包镜像

jdk8镜像制作

首先,基于centos基础镜像制作jdk8镜像,编写Dockerfile文件:(Dockerfile文件和jdk8安装包需要在同一目录)

vim Dockerfile
FROM centos:7


ENV MYPATH /usr/local
WORKDIR $MYPATH

#安装vim编辑器
RUN yum -y install vim
#安装ifconfig命令
RUN yum -y install net-tools
#安装java8及lib库
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
#ADD 是相对路径,jdk包和Dockerfile文件必须同一个目录下
ADD jdk-8u281-linux-x64.tar.gz /usr/local/java
#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_281
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH

EXPOSE 80

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

jar包镜像制作

基于上述制作好的jdk8镜像,制作jar包镜像:(Dockerfile文件和jar包需在同一目录下)

vim Dockerfile
FROM centosjava8:1.5
MAINTAINER xiaoxiaosu
#VOLUME指定临时文件目录为tmp,在主机/var/lib/docker目录下创建一个临时文件并连接到容器的tmp
VOLUME /tmp
ADD gulimall-product-0.0.1-SNAPSHOT.jar gulimall-product-0.0.1-SNAPSHOT.jar
#运行jar包
RUN bash -c 'touch gulimall-product-0.0.1-SNAPSHOT.jar'
ENTRYPOINT ["java","-jar","gulimall-product-0.0.1-SNAPSHOT.jar"]
EXPOSE 10001

八、Docker-Compose技术

简介

Docker-Compose是Docker官方开源项目,负责对Docker容器集群的快速编排。需要编写一个docker-compose.yml文件,在里面通过命令管理多个Docker容器,管理多个容器之间的协调,来共同服务于一项项目。通过docker-compose.yml进行多个容器的一键启停操作。

docker-compose需要单独安装。可参考文章:docker-compose教程(安装,使用, 快速入门)

使用步骤

1.编写Dockerfile并构建各个微服务镜像
2.使用docker-compose.yml定义一个完整的业务单元,安排好整体应用程序中各个容器服务
3.执行docker-compose up命令,一键启动项目

compose相关命令

docker-compose.yml文件编写

详细配置可参考文章:docker-compose.yml的详细解释与说明
下面是一个自己练习的demo:

version: "3"
services:
    microService: #实例名称,随便定义,不重复就行
      image: gulimall_product
      container_name: ms01 #容器名称,不写这个参数默认就是microService
      ports:
          - "10001:10001"
      volumes:
          - /app/microService:/data
      networks:
          - ceshi
      depends_on:
          - redis

    #以上命令相当于写了一个docker run命令:docker run -d -p 10001:10001 -v /app/micorService:/data --network ceshi --name ms01 gulimall_product:latest
    redis:
      image: redis
      ports:
          - "6379:6379"
      volumes:
          - /app/redis/redis.conf:/etc/redis/redis.conf
          - /app/redis/data:/data
      networks:
          - ceshi
      command: redis-server /etc/redis/redis.conf

写完yml文件后,通常执行下面命令检查编写的yml文件是否有问题:

docker-compose config -p

如果没有任何输出,代表编写yml文件没问题。在docker-compose.yml中都规定同一个自定义网络模式,在就可以使用服务名进行通信了,如mysql连接,redis连接等,都可以使用docker容器实例名配置。

一键部署,一键启停,十几个二十几个docker实例用docker-compose编排就可以。再多了就考虑引入K8s。中小型公司用docker-compose足够了。

九、监控统计

轻量级使用Portainer监控工具进行监控。docker用命令能完成的工作,都可以使用Potainer工具进行图形操作,例如拉取镜像,启动容器,查看容器详情,查看网络等等,总之一切可以用命令完成的操作,都可以用Portainer图形操作完成。

重量级的健康使用CAdvisor+InfluxDB+grafana进行监控。但是需要用到重量级监测的体谅的项目,直接使用K8s了,所以很少使用Docker的这个监控。

以上是关于Docker基础入门详解的主要内容,如果未能解决你的问题,请参考以下文章

Docker基础入门详解

Docker快速入门

Docker入门详解

Docker基础 :网络配置详解

Docker技术详解(零基础入门使用教程)

Docker 基础技术之 Linux namespace 详解