banner
Hi my new friend!

docker学习

Scroll down

docker 配置代理

使用 systemd 配置 Docker 服务

使用v2raya来代理: 安装 - v2rayA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 创建 Docker 代理配置文件
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf <<EOF
[Service]
Environment="HTTP_PROXY=socks5://127.0.0.1:20170"
Environment="HTTPS_PROXY=socks5://127.0.0.1:20170"
EOF

# 重启 Docker
sudo systemctl daemon-reload
sudo systemctl restart docker

# 测试拉取镜像(不再需要 proxychains)
docker pull praqma/network-multitool

image-20250520211246977

第二种方式:使用 daemon.json 配置文件(更省心)

1
2
3
4
5
6
7
8
9
ubuntu@ubuntu:~$ sudo cat /etc/docker/daemon.json
[sudo] password for ubuntu:
{
"proxies": {
"http-proxy": "http://192.168.196.1:10808",
"https-proxy": "http://192.168.196.1:10808",
"no-proxy": "*.example.com,127.0.0.0/8"
}
}

两种代理方式的区别

特性 第一种方式 (systemd) 第二种方式 (daemon.json)
配置路径 /etc/systemd/system/docker.service.d/http-proxy.conf /etc/docker/daemon.json
代理协议 支持 HTTP/HTTPS/SOCKS5 等 仅支持 HTTP/HTTPS
作用对象 Docker 守护进程 Docker 守护进程 容器
易用性 略复杂 简单,Docker 官方推荐
主要区别 只影响 Docker 守护进程本身,不影响容器内部。 同时影响 Docker 守护进程和容器内部

什么是守护进程?

**守护进程(Daemon)*是计算机系统中的一种特殊后台服务程序。它通常在操作系统启动时就运行,并在后台持续运行,直到系统关闭。它的主要任务是*提供某种特定的服务,并且它独立于任何用户的直接交互。

你可以把守护进程想象成一个在幕后默默工作的“管家”或“工人”。


守护进程的特点

  1. 后台运行:它没有图形界面,也不与任何终端或用户会话直接关联。它在后台默默地执行任务。
  2. 独立于用户:它不依赖于任何特定的用户登录。即使你注销了,守护进程仍然会继续运行。
  3. 提供服务:它们通常是为其他程序或用户提供服务的,比如:
    • HTTP服务器(如 Nginx 或 Apache):它是一个守护进程,持续监听80或443端口,等待并响应来自客户端的网页请求。
    • 数据库服务(如 MySQL 或 PostgreSQL):它作为守护进程在后台运行,处理来自应用程序的数据库查询和操作。
    • SSH 服务:它在后台监听端口,等待用户通过 SSH 协议远程登录。
  4. 通常以 d 结尾命名:很多守护进程的名称都以 d 结尾,这是 “daemon” 的缩写,比如:
    • sshd (SSH daemon)
    • httpd (HTTP daemon)
    • dockerd (Docker daemon)

守护进程与 Docker 的关系

在你之前的问题中,我们提到了 dockerd,这就是 Docker 守护进程

dockerd 就是一个典型的守护进程。它在后台持续运行,负责管理你的所有 Docker 容器、镜像、网络和数据卷。当你执行 docker rundocker pull 等命令时,你并不是直接在操作系统中操作,而是通过一个客户端向这个在后台运行的 dockerd 守护进程发送指令。

这就是为什么当 dockerd 没有正确运行或者你没有权限与其通信时,你的 docker 命令就会失败。

docker镜像构建

创建一个镜像

首先新建一个node.js项目,这样就会自动生成package.json文件

1
npm init -y

image-20250528105612663

由于构建服务器需要express框架,所以就直接进行安装express框架

1
npm install express

此时package.json中的依赖就会出现express的键值对,并且伴随着node_modules出现,这个文件夹会保存安装的模块

image-20250528111041838

接下来创建app.js文件

1
2
3
4
5
6
7
8
9
const express = require("express");
const app = express();
const PORT = 3000;

app.get("/",(req,res) =>{
res.send("<p>蛋家好啊</p>")
})

app.listen(PORT, () => console.log("端口3000走起!"));

可以成功运行

image-20250528112229155

接下来就是正式开始制作Dockerfile

1
2
3
4
5
6
7
FROM node:18-alpine3.15
WORKDIR /egg # 指定工作目录(不是必须)
COPY package.json . #这个"."是工作路径的相对路径
RUN npm install # 这个就会按照package.json来进行安装
COPY . . # 把本地的所有文件都复制到工作路径 docker中使用缓存package.json不会被复制两次,前面复制了就不会再次复制,而json有缓存,就不用重新去安装依赖,提高速度
EXPOSE 3000 # 暴露端口号
CMD ["node", "app.js"]

新建一个.dockerignore可以把不想在COPY . .步骤中复制进去的文件填写到里面

1
2
3
4
5
node_modules
Dockerfile
.dockerignore
.git
.gitignore

然后构建镜像

1
docker build .

使用命令查看镜像列表

1
sudo docker images

image-20250528114915895

使用sudo docker tag 镜像ID 名字来添加名字和标签(一次性添加),如果没有后边的”:”的内容就是lastest版本号

`

image-20250528115159166

docker login登录到docker hub账号,然后就可以把新建好的镜像推送到docker hub了

1
docker push dansoncut/node.js:v1.0

在构建镜像的时候就自定义名字:

1
docker build -t eggpain-image .

image-20250528132240693

删除镜像,如果有些镜像再被使用就需要使用-f强行删除(注意还是需要加上版本号,不然默认是lastest可能找不到)

1
docker rmi -f dansoncut/node.js:v1.0

image-20250528132659748

使用镜像来启动容器

非交互式启动

然后使用这个镜像来运行一个容器,如果成功会返回ID号,使用-d来设置后台运行image-20250528132850660

但是发现虽然暴露了3000端口但是这是在容器中的,并没有暴露到宿主机中,宿主机中访问3000端口没有任何服务

image-20250528133456736

这是因为Dockerfile文件中的EXPOSE只是让人知道这个镜像在用容器的某个端口,和宿主机无关,所以需要在启动端口的时候手动进行端口映射(主机端口:容器端口) 还可以在后面自定义名字(–name nishixiaozhu)

1
sudo docker run -d -p 3000:3000 --name nishixiaozhu eggpain-image

image-20250528134152450

image-20250528134449846

删除一个容器

1
2
sudo docker rm 部分id/容器名称
sudo docker rm -f 部分id/容器名称 # 强行删除

停止容器,会给容器时间来慢慢关闭

1
docker stop -t=60 容器ID或容器名

但是发现当在本地修改js文件的时候,镜像及正在运行的容器是不会改变的,这个时候就需要进行一个地址的绑定,让他去指向目标地址(注意这里的-需要绝对路径/:/工作路径)

1
sudo docker run -d -v /home/ubuntu/Desktop/:/nodejstest -p 3000:3000 --name nicaishixiaozhu eggpain-image

但是出现了新的情况,如果直接修改的话原来的node_modules会被覆盖,所以需要指明不需要同步的文件夹,就是再用-v指定一个文件夹(不同步)

1
sudo docker run -d -v /home/ubuntu/Desktop/:/nodejstest -v /egg/node_modules -p 3000:3000 --name eggpain-conner eggpain-image

但是这样如果容器中出现了新的文件夹,宿主机上也会同步(可能会被上传恶意代码)所以需要设置本地为只读模式:ro(readonly)

1
sudo docker run -d -v /home/ubuntu/Desktop/:/nodejstest:ro -v /egg/node_modules -p 3000:3000 --name eggpain-conner eggpain-image

然后会发现设置到这里还是没有用,因为镜像已经构建了,还需要自动重启去更新镜像的内容

用于自动重启 Node.js 应用当文件发生变化时(比如修改了 .js 文件)

1
npm i nodemon --save-dev

image-20250528154341842

然后修改scripts

image-20250528154552032

然后再修改Dockerfile

1
CMD ["npm", "run", "dev"]

删除原来的image在重新搭建docker build -t eggpain-image

image-20250528155442820


搞不定不太想搞了现在(哭 存个档下次再搞)

使用交互式的方法启动一个拉去的镜像

  1. docker images #查看所有镜像

    1
    2
    3
    4
    root@ubuntu:/home/ubuntu# docker images   #查看所有容器
    REPOSITORY TAG IMAGE ID CREATED SIZE
    openjdk 8 b273004037cc 3 years ago 526MB
    justrydeng/jdk8 latest b9a2453ecafd 6 years ago 482MB
  2. docker ps #查看所有正在运行的容器

    docker ps -a #查看所有的容器(包括微运行的)

    image-20250923173546414

  3. 根据已有的镜像建立一个容器表情进入容器内部的交互式shell

    1
    docker run -it -p 3000:3000 --name jdk8 justrydeng/jdk8 /bin/bash

    由于这个镜像只是简单的jdk,没有任何的网络测试环境, 所以还得自己来手动安装,由于目前是用的代理是对全局的代理,所以容器内的网络环境也无需额外考虑

    执行以下命令来安装网络工具

    1
    2
    apt-get update
    apt-get install -y iputils-ping curl net-tools
  4. 进入一个正在运行的容器的bash,可以实现多开

    1
    docker exec -it 容器名 /bin/bash
  5. 删除一个容器

    1
    2
    3
    docker ps -a #查看所有容器
    docker rm id/name #删除一个容器
    docker rm -f id/name #强制删除一个容器(可能是正在运行的也会被删除)
  6. 从本地吧文件移动到容器中

    1
    docker cp [本地文件或目录路径] [容器名或ID]:[容器内目标路径] 

docker-compose

  1. 创建镜像并启动一个容器

    启动单个容器的命令很长,如果要启动多个容器来执行协调不同的任务(mysql/nginx/apache)就需要一个统筹启动的应用,docker-compose就可以解决

    需要创建一个docker-compose.yml文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    version: "3.8"
    services:
    eggpain-container:
    build: .
    ports:
    - "3000:3000"
    volumes:
    - ./:/egg:ro
    - /egg/node_modules

    然后执行

    1
    docker-compose up -d --build

    image-20250528190423507

    image-20250528190457409

    可以发现docker-compose创建了新的镜像(nodejstest_eggpain-container_1)和新的容器(nodejstest_eggpain-container)

  2. 如果根据已有的本地镜像文件创建一个容器(不用创建镜像)

    1
    docker-compose up -d  #-d是静默执行
  3. 清除容器

    1
    2
    sudo docker-compose down -v
    # 使用 -v 选项会删除所有与容器关联的卷,这意味着所有存储在卷中的数据将被永久删除

docker网络

【入门篇】Docker网络模式Linux - Bridge | Host | None_哔哩哔哩_bilibili

如何手动关联两个容器

**Question1:**两个不同网络的docker如何通信

  1. 问题的起因是两个docker是由不同的方式启动的,一个是使用docker run而另一个使用docker-compose up

  2. **Answer: **docker中提供了解决方案,直接使用命令串联两个docker

    1. 需要找出docker-compose启动的网卡长什么样,一般是叫做**_default

      1
      docker Network ls

      image-20250925134902529

      可以轻松找到应该是nodejstest_default

    2. 使用命令docker network connect

      image-20250925135119774

      1
      docker network connect nodejstest_default jdk8

Bridge 网络

在安装docker之前的linux网卡信息是这样的,只有一张以太网网卡(ens33)和一张lo(loopback回环,只能和自己联通)

image-20250520105201812

docker安装命令:

1
sudo apt-get insatll docker.io -y | less

会发现此时多了一个docker的网卡信息:

image-20250520110133547

查看这张网卡的具体信息如下:

1
sudo docker network inspect bridge | less

image-20250520112501883

使用jq来提取一些当前有用的信息:

1
sudo docker network inspect bridge | jq '.[0] | {Name:.Name, Id:.Id, Driver:.Driver, IPAM:.IPAM.Config, Containers:.Containers, Options:.Options}'

得到以下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ubuntu@ubuntu:~/Desktop$ sudo docker network inspect bridge | jq '.[0] | {Name:.Name, Id:.Id, Driver:.Driver, IPAM:.IPAM.Config, Containers:.Containers, Options:.Options}'
{
"Name": "bridge",
"Id": "cf904d02cf0101bdf9135a9b7be444ed323fdf5f32a3a98fe7000374d5062347",
"Driver": "bridge",
"IPAM": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
],
"Containers": {},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
}
}

image-20250520114033429

此时可以看到Containers中还没有任何容器,可以添加一个功能性容器然后再来看看实力,如果本地没有这个镜像也会自动拉取

1
sudo docker run -d --name egg1 --hostname egg1 praqma/network-multitool

image-20250520211717949

然后可以使用以下命令查看容器是否正在运行

1
sudo docker ps

image-20250520211902588

然后再次使用命令查看网卡信息就会发现多了一个容器了

image-20250520212210365

此时查看接口信息会发现多了一个奇怪的接口名称,实际上这就是使用bright的网卡情况,而且对于网卡的排序也出了问题,发现顺序为4的网卡消失了

弹幕: veth虚拟以太网接口生成了一对vethx和vethy,vethx在宿主机中与虚拟网卡docker0虚拟桥接网卡相连,vethy在容器网络命名空间内,这样实现容器进程与容器之外的外部网络通信

1
2
# 需要注意的是,这个地方查看网卡信息必须使用以下命令,使用ifconfig无法查看从属关系
ip address

image-20250520212920531

使用以下命令按json格式化网卡信息,并且输出

1
ip -json address show dev vethd6a5d21 | jq .

image-20250520213238874

进入容器查看容器内的网卡信息

1
sudo docker exec -it egg1 bash

可以清晰的发现丢失的网卡4就在这里!

image-20250520214407274

使用命令查询这张网卡的具体信息

1
ip -json -detail address show dev eth0 | jq '.[0] | {ifindex:.ifindex, link_index:.link_index, ifname:.ifname, linkinfo:.linkinfo , addr_info:.addr_info}'

image-20250520215115314

可以发现对于linkinfo这个参数,就可以判断出当前接口正在和哪个接口进行连接

同样的命令查询以太网网卡是会显示null

image-20250520215356728

如果重新添加一个容器,也会发现这个容器有一张在宿主机中隐藏的虚拟网卡,而且这张网卡也是连接到veth上的,然后在宿主机的网卡信息中也会发现一张指向虚拟机的虚拟网卡,也就是这个情况

image-20250520215829355

image-20250520221709111

Bridge型

使用命令来查看现在的网络列表

1
sudo docker network ls

image-20250527170915929

创建bridge网络

1
2
3
# -d使用bridge驱动来创建
# naihe-bridge 自定义网络名称
sudo docker network create -d bridge naihe-bridge

image-20250527190208629

通过查询docker network inspect可以发现实际上两个网络的网段是不一样的

1
sudo docker network inspect 网络名称 | jq '.[0] | {Name:.Name, Id:.Id, Driver:.Driver, IPAM:.IPAM.Config, Containers:.Containers}'

image-20250527191452009

使用命令ip address查看网卡信息发现出现了一张新的网卡并且这个网卡名称和网卡id是一样的
image-20250527191809962

现在来创建一个新容器指定使用这个网卡如下

1
sudo docker run -d --name naihe1 --hostname naihe1 --network naihe-bridge praqma/network-multitool

然后查看网卡信息ip address可以发现创建了一个新的网卡使用的master网卡就是之前创建的br-9a14e1ce05d3

image-20250527192335545

可以发现网卡下出现了两个容器

image-20250527192906422

使用命令进去docker中的bash来ping另一个容器的ip发现是可以ping通的

1
sudo docker exec -it naihe1 bash

image-20250527193211984

而且实际上自定义网卡还自动配置了DNS可以直接ping主机名来实现通信,但是实际上这里指定了hostname所以不明显
image-20250527193311626

再创建一个容器但是不指定hostname再尝试ping看看能不能ping通

1
sudo docker run -d --name naihe3 --network naihe-bridge praqma/network-multitool

虚拟机死机了,重启一个停止的容器命令如下:

1
2
3
4
5
# 查看所有容器信息
sudo docker ps -a

# 启动一个停止的容器
sudo docker start naihe1

可以发现在没有指定容器名的前提下使用自定义网卡是可以实现自动配置dns的

image-20250527195439098

删除创建的网络,但是默认的网络是没有办法删除的

1
docker network rm naihe-bridge

host网络型

bridge型的网络(无论是自定义还是默认)都需要手动暴露端口才能实现,使用host网络就可以避免这个问题


host网络无法自定义创建,只能有一个,会报错

1
sudo docker network create -d host newhost

image-20250527200827615

查看网络环境发现是没有ip的

1
docker network inspect host | jq '.[0] | {Name:.Name, Id:.Id, Driver:.Driver, IPAM:.IPAM.Config, Containers:.Containers, Options:.Options}'

image-20250527211749074

如果是指定端口关联,host模式下会出问题,因为host模式是不需要端口关联的

1
sudo docker run --name egg --network host -p 8080:80 -d praqma/network-multitool

发现出现警告但是仍然可以创建新的容器

image-20250527214116672image-20250527214201495

实际上这个host网络下的容器就直接是宿主的一个应用了(只有linux下是这样的),在容器中与宿主设备中查看ip address得到的网络信息是一样的

None就是不允许进行网络通信

区别

image-20250527214551605

其他文章
cover
安装windwos到移动硬盘
  • 25/05/28
  • 23:19
  • 零碎学习
cover
vpn协议了解
  • 25/05/13
  • 10:00
  • 协议学习
目录导航 置顶
  1. 1. docker 配置代理
    1. 1.1. 使用 systemd 配置 Docker 服务
    2. 1.2. 第二种方式:使用 daemon.json 配置文件(更省心)
    3. 1.3. 两种代理方式的区别
    4. 1.4. 守护进程的特点
    5. 1.5. 守护进程与 Docker 的关系
  2. 2. docker镜像构建
    1. 2.1. 创建一个镜像
    2. 2.2. 使用镜像来启动容器
      1. 2.2.1. 非交互式启动
      2. 2.2.2. 使用交互式的方法启动一个拉去的镜像
  3. 3. docker-compose
  4. 4. docker网络
    1. 4.1. 如何手动关联两个容器
      1. 4.1.1. **Question1:**两个不同网络的docker如何通信
    2. 4.2. Bridge 网络
    3. 4.3. Bridge型
    4. 4.4. host网络型
    5. 4.5. None就是不允许进行网络通信
    6. 4.6. 区别
请输入关键词进行搜索