Docker入门的亿点点学习

前段时间花了些时间学习了亿点点docker,也算是入门了吧,顺便记了一下笔记拿出来分享给想要接触docker的兄弟们。

没有服务器的兄嘚可以去腾讯云或者阿里云领取免费的试用产品嗷,如果已经领取过了,又不想买服务器的,那就去阿里云的Linux体验馆吧,一次两小时,除了每次使用都要重新下载环境以外,也还行😂。阿里云Linux体验馆地址:linux体验馆 (aliyun.com)

一、安装docker

1.查看是否已安装docker列表

如果有则先卸载

yum list installed | grep docker        

2.安装docker

详细安装步骤可以参考官方教程:在 CentOS | 上安装 Docker 引擎Docker 文档

1.更新yum(不是必须的,如果无法下载docker则需要更新)

yum update -y

2.安装所需的软件包

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.repo

4.安装docker

yum -y install docker-ce

5.阿里云获取容器镜像加速

登录阿里云,搜索容器镜像服务,开通后去控制台找到镜像加速器,复制并执行以下命令

image

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

3.启动docker

# 启动docker
systemctl start docker    
# 查看docker运行状态
systemctl status docker
# 关闭docker
systemctl stop docker

二、卸载docker

1.停用docker

systemctl stop docker

2、查看yum安装的docker文件包

yum list installed |grep docker

3.查看docker相关的rpm源文件

rpm -qa | grep docker

4、删除所有安装的docker文件包

yum remove docker-ce docker-ce-cli containerd.io

删完之后可以再查看下docker rpm源

rpm -qa |grep docker

5、删除docker的镜像文件,默认在/var/lib/docker目录下

rm -rf /var/lib/docker

到此docker卸载就完成了,再执行docker -v就无法识别命令了。

三、docker基础命令

一、镜像操作

1.查询镜像

docker search 镜像名称

2.拉取镜像

docker pull 镜像名称:版本号
例子:
docker pull redis
docker pull redis:5.0

3.查看本地镜像

docker images

4.删除镜像、删除全部镜像

docker rmi 镜像id
# -q获取镜像的id
docker 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.0

7.标记本地镜像或归入某一仓库

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:v2

8.将镜像打包成压缩包

# -o 文件夹目录必须存在,最后为文件名
docker save -o ./test/app myimages

9.将压缩包还原成镜像

# -i 指定tar压缩包
docker load	-i ./test/app

二、容器操作

1.查看运行的容器

docker ps
# 查看全部容器
docker ps -a

2.创建并运行容器

# 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 myimage

docker run干了什么

image

3.进入容器

# 进入容器后开启一个新的终端,可以在里面操作(常用)
docker exec -it 容器名or容器id bash
# 进入容器正在执行的终端,不会启动新的进程
docker attach xxx

4.启动容器

docker start 容器名or容器id
# 重启容器
docker restart 容器名or容器id

5.停止容器

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 | 镜像id

8.查看容器日志

可以通过查看日志,得到容器启动失败或一些错误信息、原因

docker logs 容器名

9.查看容器中的进程信息

docker top 容器名or容器id

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

#             容器内部路径      宿主机路径
docker cp 容器:/home/test.txt /home

11.容器重命名

docker rename container_name new_name

四、数据卷

1.数据卷的概念

为什么要有数据卷这个东西呢,因为使用容器有存在一些问题,例如:

场景:一个mysql的容器里面有很多数据库,突然容器运行不起来了,只能删除这个容器通过镜像重新运行一个,容器删除了,容器中的数据也随之销毁,数据我们只能重新创建,这是很头疼的,也是我们不希望发生的。因此产生三个问题:

1.docker容器删除后,在容器中产生的数据如何存储备份?

2.docker容器和外部机器可以直接交换文件吗?

3.容器之间如何数据交互?

数据卷为什么可以解决这些问题:

  • 数据卷是宿主机(例如:你的虚拟机linux服务器)中的一个目录或文件
  • 当容器目录和数据卷目录绑定后,对方的修改会立即同步
  • 一个数据卷可以被多个容器同时挂载
  • 一个容器也可以挂载多个数据卷

2.数据卷的作用

数据卷是被设计用来持久化数据的,它的生命周期独立于容器,Docker不会在容器被删除后自动删除数据卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的数据卷。

  • 容器数据持久化
  • 外部机器(你的window)和容器间接通信
  • 容器之间数据交互
  • image

3.配置数据卷

创建启动容器时,使用 -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

image

4.容器数据卷

多容器进行数据共享:

  1. 方式一:多个容器挂载同一个数据卷

  2. 方式二:容器数据卷:容器c1绑定数据卷,其他的容器绑定容器c1

  3. image

命令:

# c1作为容器数据卷,不用在宿主创建目录,创建容器时会自动创建(匿名挂载)
docker run -it --name=c1 -v /volume_data redis
# 创建启动c2,c3容器,使用--volumes-form参数 设置数据卷
docker run -it --name=c2 --volumes-from c1 redis
docker run -it --name=c3 --volumes-from c1 redis
  1. 使用--volumes-from启动的容器得到的数据卷可以理解为拷贝模式的,比如c2,c3是复制了c1的数据卷,因此如果c1容器删除了,并不会影响c2和c3,数据会依然存在。

5.匿名挂载和具名挂载

1.匿名挂载

该命令下-v指的是容器内的路径,宿主机路径不填代表匿名挂载,将由系统分配,-P注意是大写

# -P随机分配端口(大写)                  匿名挂载
docker run -d -P --name c_nginx -v /etc/nginx nginx 

查看docker挂载的数据卷情况

docker volume ls

image

这些随机生成的字符串就是匿名挂载的,那么怎么查看这些匿名挂载的数据卷所在的位置呢,如下:

# docker inspect 数据卷的name
docker inspect  00c39969fe0c89841f47b2efe54f32ad79ba75e43c17b51268cb01715da17666

注意:Mountpoint就是数据卷在宿主机的位置,所有未指定目录的卷都在/var/lib/docker/volumes/xxxx/_data目录下。
image

2.具名挂载

大多数情况我们都使用具名挂载

该命令下-v后面的第一个参数只是一个名字,不是路径,如果带有/就代表路径了

docker run -d -p 81:80 --name c_nginx02 -v hasname:/etc/nginx nginx 

再查看全部数据卷docker volume ls

image

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

image

3.删除数据卷

容器正在使用的数据卷不能删除,绑定挂载的无法删除。

# docker volume rm 数据卷name
docker volume rm hasname

4.创建数据卷

创建一个数据卷

docker volume create --name=test

5.扩展

通过 -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.Docker部署MySql

1、搜索mysql镜像

docker search mysql

2、拉取镜像

docker pull mysql:8.0

3.创建容器、设置端口映射和数据卷挂载

# 宿主机创建用于存放mysql数据的数据卷目录
mkdir /root/mysql
cd /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.0

4.注意的点:

执行命令前保证当前所在的目录正确,否则下次会找不到数据卷。

关于数据卷,在/root/mysql中会生成三个文件夹,data中会存放创建的数据库。值得注意的地方是,我在测试数据卷共享数据时,我另外起了一个容器c_mysql2,端口3307:3306,然后同样绑定上面路径的数据卷并且运行成功,但是用navicat却无法连接上,报错:

image

并且进入容器c_mysql2进入/var/lib/mysql,通过创建文件发现我在容器之间的文件的确是共享了的,这可能是与mysql的运行有关。因此只需要将其中一个容器停止运行就可以正常访问并且同步数据了。

2.Docker部署Nginx

1.搜索镜像

docker search nginx

2.拉取镜像

docker pull nginx

3.创建容器,设置端口映射、数据卷映射

# 宿主机创建用于存放mysql数据的数据卷目录
mkdir /root/nginx
cd /root/nginx

注意:部署nginx时需要提前写好nginx.conf这个文件

mkdir conf
cd 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 \
nginx

4.外部机器访问容器 ip:端口

image

3.Docker部署redis

1.直接拉取镜像

docker pull redis

2.创建运行容器

前置:创建数据卷文件夹

mkdir /root/redis
cd /root/redis

提前写好配置文件

mkdir conf
cd conf
vim 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 no

port 6379


tcp-backlog 511


timeout 0

tcp-keepalive 300

# 后台运行
daemonize no

supervised no

pidfile /var/run/redis_6379.pid

loglevel notice

logfile ""

databases 16

always-show-logo yes

save 900 1
save 300 10
save 60 10000

stop-writes-on-bgsave-error yes

rdbcompression yes

rdbchecksum yes

dbfilename dump.rdb

dir ./


replica-serve-stale-data yes

replica-read-only yes

repl-diskless-sync no

repl-diskless-sync-delay 5

repl-disable-tcp-nodelay no

replica-priority 100

lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
# 是否开启数据持久化,开启则会将数据写入硬盘
appendonly no

appendfilename "appendonly.aof"

appendfsync everysec

no-appendfsync-on-rewrite no

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

aof-load-truncated yes

aof-use-rdb-preamble yes

lua-time-limit 5000

slowlog-log-slower-than 10000

slowlog-max-len 128

latency-monitor-threshold 0

notify-keyspace-events ""

hash-max-ziplist-entries 512
hash-max-ziplist-value 64

list-max-ziplist-size -2

list-compress-depth 0

set-max-intset-entries 512

zset-max-ziplist-entries 128
zset-max-ziplist-value 64

hll-sparse-max-bytes 3000

stream-node-max-bytes 4096
stream-node-max-entries 100

activerehashing yes

client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60

hz 10

dynamic-hz yes

aof-rewrite-incremental-fsync yes

rdb-save-incremental-fsync yes
requirepass 123456

运行容器

# cd 到/root/redis
cd ..

指定配置文件启动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"

4.Docker部署MSSQL

1.拉取镜像

docker pull mcr.microsoft.com/mssql/server

注意:

这边挂载数据卷有个大坑,如果直接执行以下命令你大概会得到这样的错误信息

image

经过一番搜索得到的结果大概是权限问题,我在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

六、Dockerfile常用关键字

1.FORM

格式为 FROM <image>FROM <image>:<tag>

第一条指令必须为 FROM 指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个 FROM 指令(每个镜像一次)。

2.MAINTAINER

格式为 MAINTAINER <name>,指定维护者信息。以弃用。

3.RUN

格式为 RUN <command>RUN ["executable", "param1", "param2"]

例如: RUN ["dotnet", "resotre", "YXChatApiService/YXChatApiService.csproj"]

前者将在 shell 终端中运行命令,即 /bin/sh -c;后者则使用 exec 执行。指定使用其它终端可以通过第二种方式实现,例如 RUN ["/bin/bash", "-c", "echo hello"]

每条 RUN 指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行。

4.CMD

支持三种格式

  • CMD ["executable","param1","param2"] 使用 exec 执行,推荐方式;
  • CMD command param1 param2/bin/sh 中执行,提供给需要交互的应用;
  • CMD ["param1","param2"] 提供给 ENTRYPOINT 的默认参数;

指定启动容器时执行的命令,每个 Dockerfile 只能有一条 CMD 命令。如果指定了多条命令,只有最后一条会被执行。

如果用户启动容器时候指定了运行的命令,则会覆盖掉 CMD 指定的命令。

5.EXPOSE

格式为 EXPOSE <port> [<port>...]

告诉 Docker 服务端容器暴露的端口号,供互联系统使用。在启动容器时需要通过 -P,Docker 主机会自动分配一个端口转发到指定的端口。

6.ENV

格式为 ENV <key> <value>。 指定一个环境变量,会被后续 RUN 指令使用,并在容器运行时保持。

7.ADD

格式为 ADD <src> <dest>

该命令将复制指定的 <src> 到容器中的 <dest>。 其中 <src> 可以是Dockerfile所在目录的一个相对路径;也可以是一个 URL;还可以是一个 tar 文件(自动解压为目录)。

8.COPY

格式为 COPY <src> <dest>

复制本地主机的 <src>(为 Dockerfile 所在目录的相对路径)到容器中的 <dest>

当使用本地目录为源目录时,推荐使用 COPY

9.ENTRYPOINT

两种格式:

  • ENTRYPOINT ["executable", "param1", "param2"]
  • ENTRYPOINT command param1 param2(shell中执行)。

配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。

每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。

在写Dockerfile时, ENTRYPOINT或者CMD命令会自动覆盖之前的ENTRYPOINT或者CMD命令.

10.VOLUME

格式为 VOLUME ["/data"]

多个为VOLUME ["/data","/data2"]

创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。可以预防启动容器时没有使用-v设置数据卷

注意:这里实际上是使用的匿名挂载,他会在宿主机的/var/lib/docker/volumes/xxxx/_data生成这样一个目录,xxxx是随机字符串

11.WORKDIR

格式为 WORKDIR /path/to/workdir

为后续的 RUNCMDENTRYPOINT 指令配置工作目录。

可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径

12.LABEL

格式为: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 80

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /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 final
WORKDIR /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.1
EXPOSE 80
WORKDIR /app
COPY . .
ENTRYPOINT [ "dotnet","YXChatApiService.dll" ]

将Dockerfile文件放到项目发布后的目录下,如:bin\Release\netcoreapp3.1\publish下,然后将publish文件上传到服务器执行docker build打包成镜像

七、可视化面板

1.安装portainer工具

# 这里-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

2.外部访问ip+端口

image

设置账号密码后选择本地

image

进入portainer的后台管理界面

image

学习还是推荐使用命令吧,熟能生巧。

八、发布镜像

一、发布到Docker官网

  1. docker官网注册自己的账号

  2. 登录docker账号

    # 回车,再输入密码
    docker login -u username
    # 登录成功会看到Login Succeeded字样
    
  3. 准备好一个镜像,可以是自己写Dockerfile,也可以直接拉取一个官方镜像,我这里是自己写的

    [root@iZuf6duvi53ezd1bh557idZ ~]# docker images
    REPOSITORY        TAG       IMAGE ID       CREATED          SIZE
    myjexus           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 images
    REPOSITORY        TAG       IMAGE ID       CREATED          SIZE
    hyx1229/myjexus   latest    d48ec919287d   12 minutes ago   171MB
    myjexus           v1        d48ec919287d   12 minutes ago   171MB
    

    然后发布新的镜像

     docker push hyx1229/myjexus
     # 如下就是发布成功了,然后就可以登录官网去查看自己账户下的镜像了
     [root@iZuf6duvi53ezd1bh557idZ ~]# docker push hyx1229/myjexus
    Using default tag: latest
    The push refers to repository [docker.io/hyx1229/myjexus]
    db12771375e6: Pushed 
    c47aebff94f4: Pushed 
    4fe026c953ab: Pushed 
    42755cf4ee95: Pushed 
    latest: digest: sha256:a378d3cad75ce39772f5f0a63e13d3b60a973ae60e19c7ba1539c585a4e38bf5 size: 1155
    

二、发布阿里云

1.准备工作:

  • 登录阿里云,找到容器镜像服务,创建个人实例
  • 创建命名空间(通常一个大项目为一个)
  • 创建镜像仓库(选本地仓库即可)

2.操作和发布到官网差不多,进入到仓库后有详细的命令说明,如下:

image

九、Docker网络

这部分简单了解一下吧,写的也不是很详细,要详细了解的话还是多看看资料吧!

1.容器之间通信

场景:我们用容器部署了一个项目,同时用容器部署了mssql,那么项目中的数据库连接地址我们应该怎么填?

  • 可以填宿主机的公网ip(不推荐)

  • 可以填Docker0的IP,在宿主机下通过命令ip addr可以查看到Docker0的ip地址

    Docker0:是安装Docker后,默认创建的,通常为172.17.0.1,Docker0使用的是桥接模式(Bridge ),使用的是veth-pair技术

    通过docker run启动的容器在没有指定网络的情况下,默认是通过Docker0分配的。

  • 可以填容器的ip(容器启动的ip是不固定的,并且,两个容器必须处于同一网段内才可以,比如:172.17.0.1和172.17.0.2可以互相访问,但与172.20.0.1无法互通。因此不推荐使用这种方法)

    查看容器的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 nginx
docker 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/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2      c_nginx 15643c0c776f
172.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 变更后,使用旧的条目而无法连接到正确的容器等等。

3.自定义网络

列出所有网络docker network ls,这三个是docker安装时默认创建的

[root@iZuf6gwluazepf3stdxaj3Z ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
c95d126279ef   bridge    bridge    local
d19e328067c2   host      host      local
e58fb4259b10   none      null      local

有以下几种网络模式:

  • bridge:桥接(docker默认)
  • none:不配置网络
  • host:和宿主机共享网络
  • container:容器网络连通(用的很少,不建议使用,局限性很大)

我们自己创建网络,也是用bridge桥接模式。

容器使用自定义网络

  1. 创建自定义的网桥网络

    可以指定子网、IP 地址范围、网关和其他选项。有关详细信息,请参阅 Docker 网络创建参考或输出。docker network create --help

    docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 my-net
    
  2. 将容器连接到用户定义的网桥

    docker run -P --name c_myjexus  \
    --network my-net \
    hyx1229/myjexus
    

    要将正在运行的容器连接到现有的用户定义网桥

    docker network connect my-net c_nginx
    

    此时c_myjexus和c_nginx就可以通过容器名ping通了

  3. 断开容器与网桥的连接

    docker network disconnect my-net c_nginx
    

    断开连接后,容器的网络会重新使用Docker0

  4. 删除自定义的网桥网络。如果容器当前已连接到网络,请先断开它们的连接。如:

    # 断开容器与网桥网络的连接
    docker network disconnect my-net c_myjexus
    # 删除网桥网络
    docker network rm my-net
    
  5. 查看网桥下的容器

    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 c2
PING c2 (192.168.0.4): 56 data bytes
64 bytes from 192.168.0.4: icmp_seq=0 ttl=64 time=0.112 ms
64 bytes from 192.168.0.4: icmp_seq=1 ttl=64 time=0.092 ms

[root@iZuf6gwluazepf3stdxaj3Z ~]# docker exec -it c2 ping c_myjexus
PING c_myjexus (192.168.0.2): 56 data bytes
64 bytes from 192.168.0.2: icmp_seq=0 ttl=64 time=0.081 ms
64 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_nginx
ping: 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/

posted @ 2022-02-14 22:21  不想只会CRUD的猿某人  阅读(667)  评论(0编辑  收藏  举报