前段时间花了些时间学习了亿点点docker,也算是入门了吧,顺便记了一下笔记拿出来分享给想要接触docker的兄弟们。
没有服务器的兄嘚可以去腾讯云或者阿里云领取免费的试用产品嗷,如果已经领取过了,又不想买服务器的,那就去阿里云的Linux体验馆吧,一次两小时,除了每次使用都要重新下载环境以外,也还行??。阿里云Linux体验馆地址:linux体验馆 (aliyun.com)
如果有则先卸载
yum list installed | grep docker 详细安装步骤可以参考菜鸟教程:https://www.runoob.com/docker/centos-docker-install.html
1.更新yum(不是必须的,如果无法下载docker则需要更新)
yum update -y2.安装所需的软件包
yum-utils 提供了 yum-config-manager ,并且 device mapper 存储驱动程序需要 device-mapper-persistent-data 和 lvm2
sudo yum install -y yum-utils \ device-mapper-persistent-data \ lvm2 3.设置docker包源地址(阿里云国内源)
sudo yum-config-manager \ --add-repo \ http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo4.安装docker
yum -y install docker-ce5.阿里云获取容器镜像加速
登录阿里云,搜索容器镜像服务,开通后去控制台找到镜像加速器,复制并执行以下命令

sudo mkdir -p /etc/dockersudo tee /etc/docker/daemon.json <<-'EOF'{ "registry-mirrors": ["https://fc6uhvfa.mirror.aliyuncs.com"]}EOFsudo systemctl daemon-reloadsudo systemctl restart docker# 启动dockersystemctl start docker # 查看docker运行状态systemctl status docker# 关闭dockersystemctl stop dockersystemctl stop dockeryum list installed |grep dockerrpm -qa | grep dockeryum remove docker-ce docker-ce-cli containerd.io删完之后可以再查看下docker rpm源
rpm -qa |grep dockerrm -rf /var/lib/docker到此docker卸载就完成了,再执行docker -v就无法识别命令了。
1.查询镜像
docker search 镜像名称2.拉取镜像
docker pull 镜像名称:版本号例子:docker pull redisdocker pull redis:5.03.查看本地镜像
docker images4.删除镜像、删除全部镜像
docker rmi 镜像id# -q获取镜像的iddocker rmi $(docker images -q)docker rmi `docker images -q`5.创建本地镜像
找到你需要构建镜像的Dockerfile文件的目录位置,cd进去
# -t 镜像名称 .是在指定镜像构建过程中的上下文环境的目录,并非指的本地目录# -f ./dockerfile(dockerfile的路径)docker build -t myimage .这里的"."想要理解的,需要了解一下镜像构建上下文(Context),参考地址:如何理解docker镜像build中的上下文 - 初级编程 - 博客园 (cnblogs.com)
6.将容器提交为镜像
镜像是多层存储,每一层是在前一层的基础上进行的修改;而容器同样也是多层存储,是在以镜像为基础层,在其基础上加一层作为容器运行时的存储层。
当我们需要通过一个基础镜像做开发,开发完希望打包成一个镜像以后复用时,我们可以先根据该镜像启动容器,做行为操作后再将容器提交为镜像。
# docker commit -a="作者" -m="消息" 容器id or name 新镜像名称docker commit -a="test@163.com" -m="test commit" a404c6c174a2 tomcat_test:1.07.标记本地镜像或归入某一仓库
docker tag : 可标记本地镜像,可将其归入某一仓库。
语法:docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
# 例:归入某一仓库 docker用户id/仓库(没有该仓库则默认创建)docker tag mynginx:v1 hyx1229/mynginx# 例:打个标记docker tag myningx:v1 myningx-v2:v28.将镜像打包成压缩包
# -o 文件夹目录必须存在,最后为文件名docker save -o ./test/app myimages9.将压缩包还原成镜像
# -i 指定tar压缩包docker load -i ./test/app1.查看运行的容器
docker ps# 查看全部容器docker ps -a2.创建并运行容器
# i保持容器运行 t为容器分配一个伪终端 name后面是容器名称 -it默认进入容器,退出容器,容器也会停止运行docker run -it --name=container01 redis# d容器在后台运行 需要使用docker exec container02进入容器 容器不会关闭docker run -id --name=container02 redis# -it创建的容器一般称为交互式容器 -id创建的容器一般称为守护式容器# 宿主机端口号:容器内部暴露的端口号docker run -id --name=container03 -p 8088:80 myimagedocker run干了什么

3.进入容器
# 进入容器后开启一个新的终端,可以在里面操作(常用)docker exec -it 容器名or容器id bash# 进入容器正在执行的终端,不会启动新的进程docker attach xxx4.启动容器
docker start 容器名or容器id# 重启容器docker restart 容器名or容器id5.停止容器
docker stop 容器名or容器id# 停止正在运行的全部容器docker stop $(docker ps -q)6.删除容器、删除全部容器
docker rm 容器名or容器id# 删除全部容器 -f 强制删除docker rm -f $(docker ps -aq)7.查看容器信息或镜像信息
docker inspect 容器名or容器id | 镜像id8.查看容器日志
可以通过查看日志,得到容器启动失败或一些错误信息、原因
docker logs 容器名9.查看容器中的进程信息
docker top 容器名or容器id10.从容器内拷贝文件到主机上
# 容器内部路径 宿主机路径docker cp 容器:/home/test.txt /home11.容器重命名
docker rename container_name new_name为什么要有数据卷这个东西呢,因为使用容器有存在一些问题,例如:
场景:一个mysql的容器里面有很多数据库,突然容器运行不起来了,只能删除这个容器通过镜像重新运行一个,容器删除了,容器中的数据也随之销毁,数据我们只能重新创建,这是很头疼的,也是我们不希望发生的。因此产生三个问题:
1.docker容器删除后,在容器中产生的数据如何存储备份?
2.docker容器和外部机器可以直接交换文件吗?
3.容器之间如何数据交互?
数据卷为什么可以解决这些问题:
数据卷是被设计用来持久化数据的,它的生命周期独立于容器,Docker不会在容器被删除后自动删除数据卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的数据卷。

创建启动容器时,使用 -v 参数 设置数据卷
docker run containerName -v 宿主机目录(文件):容器内目录(文件)注意:
目录必须是绝对路径
目录不存在会自动创建
可以挂载多个数据卷,多个-v。例如:
docker run -it --name=c1 -v /xhnbzdl/docker_data:/container_data/d1 -v /xhnbzdl/vueDemo:/container_data/d2 redis挂载绑定时无法重复绑定容器的某一个目录,例如:
# 使用了两个/container_data/d1,会报错docker run -it --name=c2 -v /xhnbzdl/docker_data:/container_data/d1 -v /xhnbzdl/vueDemo:/container_data/d1 redis但宿主机的目录可以重复绑定在容器内的不同路径下,例如:
docker run -it --name=c2 -v /xhnbzdl/docker_data:/container_data/d1 -v /xhnbzdl/docker_data:/container_data/d2 redis查看数据卷挂载
docker inspect 容器name
多容器进行数据共享:
方式一:多个容器挂载同一个数据卷
方式二:容器数据卷:容器c1绑定数据卷,其他的容器绑定容器c1

命令:
# c1作为容器数据卷,不用在宿主创建目录,创建容器时会自动创建(匿名挂载)docker run -it --name=c1 -v /volume_data redis# 创建启动c2,c3容器,使用--volumes-form参数 设置数据卷docker run -it --name=c2 --volumes-from c1 redisdocker run -it --name=c3 --volumes-from c1 redis该命令下-v指的是容器内的路径,宿主机路径不填代表匿名挂载,将由系统分配,-P注意是大写
# -P随机分配端口(大写) 匿名挂载docker run -d -P --name c_nginx -v /etc/nginx nginx 查看docker挂载的数据卷情况
docker volume ls
这些随机生成的字符串就是匿名挂载的,那么怎么查看这些匿名挂载的数据卷所在的位置呢,如下:
# docker inspect 数据卷的namedocker inspect 00c39969fe0c89841f47b2efe54f32ad79ba75e43c17b51268cb01715da17666注意:Mountpoint就是数据卷在宿主机的位置,所有未指定目录的卷都在/var/lib/docker/volumes/xxxx/_data目录下。
大多数情况我们都使用具名挂载
该命令下-v后面的第一个参数只是一个名字,不是路径,如果带有/就代表路径了
docker run -d -p 81:80 --name c_nginx02 -v hasname:/etc/nginx nginx 再查看全部数据卷docker volume ls

这个hasname就是具名挂载的,可以再查看实际挂载的位置docker insepct hasname

容器正在使用的数据卷不能删除,绑定挂载的无法删除。
# docker volume rm 数据卷namedocker volume rm hasname创建一个数据卷
docker volume create --name=test通过 -v 容器内路径:ro 、rw 改变读写权限
ro readonly #只读
rw readwrite #可读可写
# 容器内只读,无法添加文件或修改文件操作,只能从宿主机来操作docker run -d -P --name c_nginx03 -v hasname-nginx:/etc/nginx:ro nginx# 容器内可读写操作docker run -d -P --name c_nginx03 -v hasname-nginx:/etc/nginx:rw nginx| 命令 | 描述 |
|---|---|
| docker volume create | 创建一个卷 |
| docker volume inspect | 显示一个或多个卷的详细信息 |
| docker volume ls | 列出卷 |
| docker volume prune | 删除所有未使用的卷 |
| docker volume rm | 删除一个或多个卷 |
1、搜索mysql镜像
docker search mysql2、拉取镜像
docker pull mysql:8.03.创建容器、设置端口映射和数据卷挂载
# 宿主机创建用于存放mysql数据的数据卷目录mkdir /root/mysqlcd /root/mysql# $PWD 代表当前路径(只能是大写的PWD),我是先cd到/root/mysql路径的,$PWD==/root/mysql# -e 设置环境变量docker run -id \-p 3306:3306 \--name=c_mysql \-v $PWD/conf:/ect/mysql/conf.d \-v $PWD/logs:/logs \-v $PWD/data:/var/lib/mysql \-e MYSQL_ROOT_PASSWORD=123456 \mysql:8.04.注意的点:
执行命令前保证当前所在的目录正确,否则下次会找不到数据卷。
关于数据卷,在/root/mysql中会生成三个文件夹,data中会存放创建的数据库。值得注意的地方是,我在测试数据卷共享数据时,我另外起了一个容器c_mysql2,端口3307:3306,然后同样绑定上面路径的数据卷并且运行成功,但是用navicat却无法连接上,报错:

并且进入容器c_mysql2进入/var/lib/mysql,通过创建文件发现我在容器之间的文件的确是共享了的,这可能是与mysql的运行有关。因此只需要将其中一个容器停止运行就可以正常访问并且同步数据了。
1.搜索镜像
docker search nginx2.拉取镜像
docker pull nginx3.创建容器,设置端口映射、数据卷映射
# 宿主机创建用于存放mysql数据的数据卷目录mkdir /root/nginxcd /root/nginx注意:部署nginx时需要提前写好nginx.conf这个文件
mkdir confcd conf# 创建nginx的配置文件vim nginx.conf粘贴以下内容:
这个是删除注释后的nginx的默认配置,复制完nginx.conf后记得cd .. 回到/root/nginx目录
worker_processes 1;events { worker_connections 1024;}http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }}创建前记得检查端口是否被占用,这里我的80端口被占用了所以用81
端口占用解决办法:
# 1.查找被占用的端口netstat -tln netstat -tln | grep 80# 2.查看端口属于哪个程序?端口被哪个进程占用lsof -i :80# 3.杀掉占用端口的进程kill -9 进程id 创建运行容器
docker run -id --name=c_nginx \-p 81:80 \-v $PWD/conf/nginx.conf:/etc/nginx/nginx.conf \-v $PWD/logs:/var/log/nginx \-v $PWD/app:/usr/share/nginx/app \nginx4.外部机器访问容器 ip:端口

1.直接拉取镜像
docker pull redis2.创建运行容器
前置:创建数据卷文件夹
mkdir /root/rediscd /root/redis提前写好配置文件
mkdir confcd confvim redis.conf复制以下代码,redis的默认配置,配置需要稍作修改
注意:
在docker中启动redis一定要把:daemonize 设置为 no,这个很重要,如果不是no, docker会一直启动失败,原因是docker本身需要后台运行,而这个配置选项也是以守护进程启动,两者会冲突。
数据持久化:appendonly可以设置为no,那么docker命令启动时则需要加上--appendonly yes。
密码验证:requirepass可以用默认的,默认是没有密码验证,如果需要则在配置中加上 requirepass 123456
不加则可以在docker命令中加参数--requirepass “123456"
# bind 只设置为0.0.0.0 将不能远程连接# bind 0.0.0.0# protected-mode 设置为no,关闭保护模式protected-mode noport 6379tcp-backlog 511timeout 0tcp-keepalive 300# 后台运行daemonize nosupervised nopidfile /var/run/redis_6379.pidloglevel noticelogfile ""databases 16always-show-logo yessave 900 1save 300 10save 60 10000stop-writes-on-bgsave-error yesrdbcompression yesrdbchecksum yesdbfilename dump.rdbdir ./replica-serve-stale-data yesreplica-read-only yesrepl-diskless-sync norepl-diskless-sync-delay 5repl-disable-tcp-nodelay noreplica-priority 100lazyfree-lazy-eviction nolazyfree-lazy-expire nolazyfree-lazy-server-del noreplica-lazy-flush no# 是否开启数据持久化,开启则会将数据写入硬盘appendonly noappendfilename "appendonly.aof"appendfsync everysecno-appendfsync-on-rewrite noauto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mbaof-load-truncated yesaof-use-rdb-preamble yeslua-time-limit 5000slowlog-log-slower-than 10000slowlog-max-len 128latency-monitor-threshold 0notify-keyspace-events ""hash-max-ziplist-entries 512hash-max-ziplist-value 64list-max-ziplist-size -2list-compress-depth 0set-max-intset-entries 512zset-max-ziplist-entries 128zset-max-ziplist-value 64hll-sparse-max-bytes 3000stream-node-max-bytes 4096stream-node-max-entries 100activerehashing yesclient-output-buffer-limit normal 0 0 0client-output-buffer-limit replica 256mb 64mb 60client-output-buffer-limit pubsub 32mb 8mb 60hz 10dynamic-hz yesaof-rewrite-incremental-fsync yesrdb-save-incremental-fsync yesrequirepass 123456运行容器
# cd 到/root/rediscd ..指定配置文件启动redis
docker run -id -p 6379:6379 --name=c_redis \-v $PWD/conf/redis.conf:/etc/redis/redis.conf \-v $PWD/data:/data \-v $PWD/logs:/logs \redis:latest redis-server /etc/redis/redis.conf ## 可选参数 --appendonly yes --requirepass "bbb123456"1.拉取镜像
docker pull mcr.microsoft.com/mssql/server注意:
这边挂载数据卷有个大坑,如果直接执行以下命令你大概会得到这样的错误信息

经过一番搜索得到的结果大概是权限问题,我在github上所得到的解决方案是
# 那么我们需要先创建数据卷的路径,再设置chown 10001:0 [the-path-of-the-mounted-volume](数据卷的路径)2.创建运行容器
docker run -id --name=c_mssql -e 'ACCEPT_EULA=Y' \-e 'MSSQL_SA_PASSWORD=Xhnbzdl0114' \-p 1433:1433 \-v /root/docker_data/mssql:/var/opt/mssql \mcr.microsoft.com/mssql/server格式为 FROM <image>或FROM <image>:<tag>。
第一条指令必须为 FROM 指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个 FROM 指令(每个镜像一次)。
格式为 MAINTAINER <name>,指定维护者信息。以弃用。
格式为 RUN <command> 或RUN ["executable", "param1", "param2"]。
例如: RUN ["dotnet", "resotre", "YXChatApiService/YXChatApiService.csproj"]。
前者将在 shell 终端中运行命令,即 /bin/sh -c;后者则使用 exec 执行。指定使用其它终端可以通过第二种方式实现,例如 RUN ["/bin/bash", "-c", "echo hello"]。
每条 RUN 指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行。
支持三种格式
CMD ["executable","param1","param2"] 使用 exec 执行,推荐方式;CMD command param1 param2 在 /bin/sh 中执行,提供给需要交互的应用;CMD ["param1","param2"] 提供给 ENTRYPOINT 的默认参数;指定启动容器时执行的命令,每个 Dockerfile 只能有一条 CMD 命令。如果指定了多条命令,只有最后一条会被执行。
如果用户启动容器时候指定了运行的命令,则会覆盖掉 CMD 指定的命令。
格式为 EXPOSE <port> [<port>...]。
告诉 Docker 服务端容器暴露的端口号,供互联系统使用。在启动容器时需要通过 -P,Docker 主机会自动分配一个端口转发到指定的端口。
格式为 ENV <key> <value>。 指定一个环境变量,会被后续 RUN 指令使用,并在容器运行时保持。
格式为 ADD <src> <dest>。
该命令将复制指定的 <src> 到容器中的 <dest>。 其中 <src> 可以是Dockerfile所在目录的一个相对路径;也可以是一个 URL;还可以是一个 tar 文件(自动解压为目录)。
格式为 COPY <src> <dest>。
复制本地主机的 <src>(为 Dockerfile 所在目录的相对路径)到容器中的 <dest>。
当使用本地目录为源目录时,推荐使用 COPY。
两种格式:
ENTRYPOINT ["executable", "param1", "param2"]ENTRYPOINT command param1 param2(shell中执行)。配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。
每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。
在写Dockerfile时, ENTRYPOINT或者CMD命令会自动覆盖之前的ENTRYPOINT或者CMD命令.
格式为 VOLUME ["/data"]。
多个为VOLUME ["/data","/data2"]
创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。可以预防启动容器时没有使用-v设置数据卷
注意:这里实际上是使用的匿名挂载,他会在宿主机的/var/lib/docker/volumes/xxxx/_data生成这样一个目录,xxxx是随机字符串
格式为 WORKDIR /path/to/workdir。
为后续的 RUN、CMD、ENTRYPOINT 指令配置工作目录。
可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径
格式为:LABEL <key>=<value> <key>=<value>
取代了MAINTAINER,将元数据添加到镜像
该示例为.net core3.1 WebApi项目,在vs中点击添加docker支持,自动生成的dockerfile文件。这个文件有点坑,执行docker build 前记得把dockerfile移动到项目的上一级目录。
注意:文件中的每一步,就是镜像中的一层。该文件用到了多构建阶段。
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.# 拉取基础镜像,.net的可以是sdk或runtime as 别名 当前镜像有运行时FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base# 容器内部:设置工作目录,网上说可以理解为cd,如果没有该目录则会自动创建WORKDIR /app# 暴露的端口EXPOSE 80FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS buildWORKDIR /src# 上下文中的路径 容器路径,默认会创建目录 /src/YXChatApiService/COPY ["YXChatApiService/YXChatApiService.csproj", "YXChatApiService/"]# 执行linux命令 还原nuget包RUN dotnet restore "YXChatApiService/YXChatApiService.csproj"# 拷贝上下文中当前目录下的所有文件到/src下COPY . .WORKDIR "/src/YXChatApiService"# 执行编译项目RUN dotnet build "YXChatApiService.csproj" -c Release -o /app/build# 基于某一个镜像FROM build AS publish# 执行发布命令RUN dotnet publish "YXChatApiService.csproj" -c Release -o /app/publish# 基于第一层镜像FROM base AS finalWORKDIR /app# 从第三层镜像中的/app/publish下拷贝,到/app目录下COPY --from=publish /app/publish .ENTRYPOINT ["dotnet", "YXChatApiService.dll"]我们部署.net的项目时,不想直接将源代码打包成镜像,因为那样需要下载sdk等镜像,如果我们希望将编译打包后的项目去打包镜像,可以修改dockefile为,这样可以dockerfile和打包后的代码放在一个目录下。
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1EXPOSE 80WORKDIR /appCOPY . .ENTRYPOINT [ "dotnet","YXChatApiService.dll" ]将Dockerfile文件放到项目发布后的目录下,如:bin\Release\netcoreapp3.1\publish下,然后将publish文件上传到服务器执行docker build打包成镜像
# 这里-v必填,因为portainer需要根据这个文件获取信息,地址也是固定写法# --restart=always重启docker时,自动启动相关容器。docker run -id -p 9000:9000 --name=c_portainer \--restart=always -v /var/run/docker.sock:/var/run/docker.sock \--privileged=true portainer/portainer
设置账号密码后选择本地

进入portainer的后台管理界面

学习还是推荐使用命令吧,熟能生巧。
docker官网注册自己的账号
登录docker账号
# 回车,再输入密码docker login -u username# 登录成功会看到Login Succeeded字样准备好一个镜像,可以是自己写Dockerfile,也可以直接拉取一个官方镜像,我这里是自己写的
[root@iZuf6duvi53ezd1bh557idZ ~]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEmyjexus v1 d48ec919287d 12 minutes ago 171MB执行命令docker push myjexus,如果报错如下:
denied: requested access to the resource is denied先检查是否登录成功,如果是登录成功的状态,那么应该将镜像改到自己的账户下,方法如下:
docker tag myjexus:v1 hyx1229/myjexus# 再查看镜像[root@iZuf6duvi53ezd1bh557idZ ~]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEhyx1229/myjexus latest d48ec919287d 12 minutes ago 171MBmyjexus v1 d48ec919287d 12 minutes ago 171MB然后发布新的镜像
docker push hyx1229/myjexus # 如下就是发布成功了,然后就可以登录官网去查看自己账户下的镜像了 [root@iZuf6duvi53ezd1bh557idZ ~]# docker push hyx1229/myjexusUsing default tag: latestThe push refers to repository [docker.io/hyx1229/myjexus]db12771375e6: Pushed c47aebff94f4: Pushed 4fe026c953ab: Pushed 42755cf4ee95: Pushed latest: digest: sha256:a378d3cad75ce39772f5f0a63e13d3b60a973ae60e19c7ba1539c585a4e38bf5 size: 11551.准备工作:
2.操作和发布到官网差不多,进入到仓库后有详细的命令说明,如下:

这部分简单了解一下吧,写的也不是很详细,要详细了解的话还是多看看资料吧!
场景:我们用容器部署了一个项目,同时用容器部署了mssql,那么项目中的数据库连接地址我们应该怎么填?
可以填宿主机的公网ip(不推荐)
可以填Docker0的IP,在宿主机下通过命令ip addr可以查看到Docker0的ip地址
Docker0:是安装Docker后,默认创建的,通常为172.17.0.1,Docker0使用的是桥接模式(Bridge ),使用的是veth-pair技术
通过docker run启动的容器在没有指定网络的情况下,默认是通过Docker0分配的。
可以填容器的ip(容器启动的ip是不固定的,不推荐)
查看容器的ip通过docker inspect 容器id,如下:可以看到Gateway的地址是Docker0的ip,“IPAddress”就是容器的ip
"Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "ef45d57e9dccf292414db59a2eb6c4c4f7f4a8a3381d42a2647d240a20d2d283", "EndpointID": "8333be2f4597db117f562e20b17016647d212ac4afd164c3709f12e4cb2094cd", "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 }}通过容器名,使用自定义网络或--link
除了通过上面写ip的方式,我们还可以在docker run的时候使用--link参数指定与某个容器的ip进行互通,如下:
docker run -id -P --name=c_nginx nginxdocker run -id -P --name=c_myjexus --link c_nginx hyx1229/myjexus这样我们就可以在容器c_myjexus中ping通我们的c_nginx,并且我们不需要知道c_nginx这个容的ip是多少,可以直接通过容器名ping通,测试:
docker exec -it c_myjexus ping c_nginx原理:--link做了什么
我们查看容器c_myjexus的host文件,docker exec -it c_myjexus cat /etc/hosts,如下:
[root@iZuf6gwluazepf3stdxaj3Z ~]# docker exec -it c_myjexus cat /etc/hosts127.0.0.1 localhost::1 localhost ip6-localhost ip6-loopbackfe00::0 ip6-localnetff00::0 ip6-mcastprefixff02::1 ip6-allnodesff02::2 ip6-allrouters172.17.0.2 c_nginx 15643c0c776f172.17.0.3 31a765e18cb3他将c_nginx的ip追加到了hosts的配置中,并且起了别名,那么反向c_nginx去ping我们的c_myjexus能通吗?不能,因为没有配置,只能通过ip去ping。
为什么说他过时了呢?
因为--link使用的是docker0,因此实际上默认情况下所有容器都是可以互联的,没有隔离,当然这样安全性不好。使用 --link 就很可能还在用默认桥接网络,这很不安全,所有容器都没有适度隔离,用自定义网络才比较方便互联隔离。其次,修改 /etc/hosts 文件有很多弊病。比如,高频繁的容器启停环境时,容易产生竞争冒险,导致 /etc/hosts 文件损坏,出现访问故障;或者有些应用发现是来自于 /etc/hosts 文件后,就假定其为静态文件,而缓存结果不再查询,从而导致容器启停 IP 变更后,使用旧的条目而无法连接到正确的容器等等。
列出所有网络docker network ls,这三个是docker安装时默认创建的
[root@iZuf6gwluazepf3stdxaj3Z ~]# docker network lsNETWORK ID NAME DRIVER SCOPEc95d126279ef bridge bridge locald19e328067c2 host host locale58fb4259b10 none null local有以下几种网络模式:
我们自己创建网络,也是用bridge桥接模式。
容器使用自定义网络
创建自定义的网桥网络
可以指定子网、IP 地址范围、网关和其他选项。有关详细信息,请参阅 Docker 网络创建参考或输出。docker network create --help
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 my-net将容器连接到用户定义的网桥
docker run -P --name c_myjexus \--network my-net \hyx1229/myjexus要将正在运行的容器连接到现有的用户定义网桥
docker network connect my-net c_nginx此时c_myjexus和c_nginx就可以通过容器名ping通了
断开容器与网桥的连接
docker network disconnect my-net c_nginx断开连接后,容器的网络会重新使用Docker0
删除自定义的网桥网络。如果容器当前已连接到网络,请先断开它们的连接。如:
# 断开容器与网桥网络的连接docker network disconnect my-net c_myjexus# 删除网桥网络docker network rm my-net查看网桥下的容器
docker network inspect my-net# 可以看到以下内容"Containers": { "632e11b4d57fa658e2a4ad7d78f4cf504f275d5511a5fecfae76122b74b06940": { "Name": "c_myjexus", "EndpointID": "011b3a76ada13aa038fa45030f11c73439f4ca020f5e967e55d2a79c5d73061a", "MacAddress": "02:42:c0:a8:00:02", "IPv4Address": "192.168.0.2/16", "IPv6Address": "" }, "da534f7ca8caf3535a58529216b4be15f4cc8068fb81f31514e0d7050db44bf1": { "Name": "c2", "EndpointID": "83cd91251b42e553206714c92ae5a7e7395edade69a23d986c05b60b975f41f8", "MacAddress": "02:42:c0:a8:00:04", "IPv4Address": "192.168.0.4/16", "IPv6Address": "" }}上面我们通过自定义网络,启动了一个c_myjexus,这时我们再启动一个c2
docker run -P --name c2 \--network my-net \hyx1229/myjexus此时测试c_myjexus和c2使用的是同一个网桥网络,我们可以测试ping,两个容器都可以互相使用容器名ping通
[root@iZuf6gwluazepf3stdxaj3Z ~]# docker exec -it c_myjexus ping c2PING c2 (192.168.0.4): 56 data bytes64 bytes from 192.168.0.4: icmp_seq=0 ttl=64 time=0.112 ms64 bytes from 192.168.0.4: icmp_seq=1 ttl=64 time=0.092 ms[root@iZuf6gwluazepf3stdxaj3Z ~]# docker exec -it c2 ping c_myjexusPING c_myjexus (192.168.0.2): 56 data bytes64 bytes from 192.168.0.2: icmp_seq=0 ttl=64 time=0.081 ms64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=0.105 ms那么使用自定义网络的容器是否可以ping通docker0起的容器呢?答案是不可以
[root@iZuf6gwluazepf3stdxaj3Z ~]# docker exec -it c2 ping c_nginxping: unknown host那么如何让他们之间互通呢,也是通过docker network connect my-net c_nginx命令。执行命令后我们查看该容器docker insepct c_nginx
发现它拥有两个网桥,此时就可以互通了,一个容器两个ip
"Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "c95d126279ef720cf8f1d02ee1a80a7a2a2d66927897299f3ef853572517a88b", "EndpointID": "ad2cc6e304f81aa5f1060c3618654cd78631cad1f2a5473f2bdf4d5b62af4d04", "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 }, "my-net": { "IPAMConfig": {}, "Links": null, "Aliases": [ "15643c0c776f" ], "NetworkID": "01fee2be9ef852fc48c619ba6d5a6319e7782dcf6ab5bc4722e47814c6e66fe2", "EndpointID": "76f2705bdc419e657f2844be7e796c8879223e63aabbb8a9958171c07a79300c", "Gateway": "192.168.0.1", "IPAddress": "192.168.0.3", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:c0:a8:00:03", "DriverOpts": {} }}注:那么使用自定义网络和使用Docker0的区别就显而易见,比如使用自定义网络容器之间可以直接通过容器名ping通。
比如我有一个redis的集群,就可以打一个网络。还有一个mssql的集群,也可以搭一个网络。网络之间是互相隔离的。不同集群使用不同网络,集群都是健康的。
有关于docker网络的东西还有很多,这里只是简单记录一下。
了解了docker网络之后,应该是入门了docker,接下来就可以学习docker-compose以及docker swarm啦。
本文是自己学习过程中的一些记录,部分参考了b站狂神、黑马、官方文档、以及各路大佬的博客。
编写不易,希望能收获大家的点赞推荐,谢谢!
本文首发链接为:https://www.cnblogs.com/hyx1229/p/15894421.html
作者:不想只会CURD的猿某人
更多原著文章请参考:https://www.cnblogs.com/hyx1229/