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基本操作命令大全
系统级别命令
镜像相关命令
- 查看本地仓库镜像:
docker images
输出字段及含义如下图:
其中一个镜像可以有多个TAG版本存在。使用某个版本,可以通过镜像名称:TAG
来指定。当版本为latest时,可以省略:TAG。否则必须使用镜像名称:TAG
。
- 查询远程仓库镜像:
docker search xxx
可以列出镜像,如下图所示:
其中OFFICAL代表是否官方。优先选择官方镜像进行拉取。这里只是搜索镜像,并不包含具体版本号,一般镜像包含了各个版本。我们可以直接在镜像名后面加我们想要的版本即可。如果不加版本,默认拉取latest版本。
在Docker Hub官网,也可以搜索某个镜像。
- 拉取镜像到本地:
docker pull 镜像名字[:TAG]
如果不加TAG,默认拉取最新的。
- 删除镜像:
docker -rmi 镜像名字ID
镜像启动的所有实例必须停止运行才可以删除镜像。
容器相关命令
- 启动容器命令:
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镜像的意思。
- 进入某个容器命令
上面讲到启动一个后台运行的容器,那么如果 想进入这个容器做交互,应该如何进去呢?执行以下命令:
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的大致流程如下:
- docker从基础镜像运行一个容器
- 执行每一个指令对基础镜像进行修改
- 执行类似docker commit命令提交一个新的镜像层
- docker再基于新镜像运行一个新容器
- 执行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基础入门详解的主要内容,如果未能解决你的问题,请参考以下文章