docker 配置代理
使用 systemd
配置 Docker 服务
使用v2raya来代理: 安装 - v2rayA
1 | # 创建 Docker 代理配置文件 |
第二种方式:使用 daemon.json
配置文件(更省心)
1 | ubuntu@ubuntu:~$ sudo cat /etc/docker/daemon.json |
两种代理方式的区别
特性 | 第一种方式 (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)*是计算机系统中的一种特殊后台服务程序。它通常在操作系统启动时就运行,并在后台持续运行,直到系统关闭。它的主要任务是*提供某种特定的服务,并且它独立于任何用户的直接交互。
你可以把守护进程想象成一个在幕后默默工作的“管家”或“工人”。
守护进程的特点
- 后台运行:它没有图形界面,也不与任何终端或用户会话直接关联。它在后台默默地执行任务。
- 独立于用户:它不依赖于任何特定的用户登录。即使你注销了,守护进程仍然会继续运行。
- 提供服务:它们通常是为其他程序或用户提供服务的,比如:
- HTTP服务器(如 Nginx 或 Apache):它是一个守护进程,持续监听80或443端口,等待并响应来自客户端的网页请求。
- 数据库服务(如 MySQL 或 PostgreSQL):它作为守护进程在后台运行,处理来自应用程序的数据库查询和操作。
- SSH 服务:它在后台监听端口,等待用户通过 SSH 协议远程登录。
- 通常以
d
结尾命名:很多守护进程的名称都以d
结尾,这是 “daemon” 的缩写,比如:
sshd
(SSH daemon)httpd
(HTTP daemon)dockerd
(Docker daemon)守护进程与 Docker 的关系
在你之前的问题中,我们提到了
dockerd
,这就是 Docker 守护进程。
dockerd
就是一个典型的守护进程。它在后台持续运行,负责管理你的所有 Docker 容器、镜像、网络和数据卷。当你执行docker run
、docker pull
等命令时,你并不是直接在操作系统中操作,而是通过一个客户端向这个在后台运行的dockerd
守护进程发送指令。这就是为什么当
dockerd
没有正确运行或者你没有权限与其通信时,你的docker
命令就会失败。
docker镜像构建
创建一个镜像
首先新建一个node.js
项目,这样就会自动生成package.json
文件
1 | npm init -y |
由于构建服务器需要express框架,所以就直接进行安装express框架
1 | npm install express |
此时package.json
中的依赖就会出现express的键值对,并且伴随着node_modules出现,这个文件夹会保存安装的模块
接下来创建app.js
文件
1 | const express = require("express"); |
可以成功运行
接下来就是正式开始制作Dockerfile
1 | FROM node:18-alpine3.15 |
新建一个.dockerignore
可以把不想在COPY . .
步骤中复制进去的文件填写到里面
1 | node_modules |
然后构建镜像
1 | docker build . |
使用命令查看镜像列表
1 | sudo docker images |
使用sudo docker tag 镜像ID 名字
来添加名字和标签(一次性添加),如果没有后边的”:”的内容就是lastest版本号
`
docker login登录到docker hub账号,然后就可以把新建好的镜像推送到docker hub了
1 | docker push dansoncut/node.js:v1.0 |
在构建镜像的时候就自定义名字:
1 | docker build -t eggpain-image . |
删除镜像,如果有些镜像再被使用就需要使用-f
强行删除(注意还是需要加上版本号,不然默认是lastest可能找不到)
1 | docker rmi -f dansoncut/node.js:v1.0 |
使用镜像来启动容器
非交互式启动
然后使用这个镜像来运行一个容器,如果成功会返回ID号,使用-d
来设置后台运行
但是发现虽然暴露了3000端口但是这是在容器中的,并没有暴露到宿主机中,宿主机中访问3000端口没有任何服务
这是因为Dockerfile
文件中的EXPOSE
只是让人知道这个镜像在用容器的某个端口,和宿主机无关,所以需要在启动端口的时候手动进行端口映射(主机端口:容器端口) 还可以在后面自定义名字(–name nishixiaozhu)
1 | sudo docker run -d -p 3000:3000 --name nishixiaozhu eggpain-image |
删除一个容器
1 | sudo docker rm 部分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 |
然后修改scripts
然后再修改Dockerfile
1 | CMD ["npm", "run", "dev"] |
删除原来的image在重新搭建docker build -t eggpain-image
搞不定不太想搞了现在(哭 存个档下次再搞)
使用交互式的方法启动一个拉去的镜像
docker images
#查看所有镜像1
2
3
4root@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 482MBdocker ps
#查看所有正在运行的容器docker ps -a
#查看所有的容器(包括微运行的)根据已有的镜像建立一个容器表情进入容器内部的交互式shell
1
docker run -it -p 3000:3000 --name jdk8 justrydeng/jdk8 /bin/bash
由于这个镜像只是简单的jdk,没有任何的网络测试环境, 所以还得自己来手动安装,由于目前是用的代理是对全局的代理,所以容器内的网络环境也无需额外考虑
执行以下命令来安装网络工具
1
2apt-get update
apt-get install -y iputils-ping curl net-tools进入一个正在运行的容器的bash,可以实现多开
1
docker exec -it 容器名 /bin/bash
删除一个容器
1
2
3docker ps -a #查看所有容器
docker rm id/name #删除一个容器
docker rm -f id/name #强制删除一个容器(可能是正在运行的也会被删除)从本地吧文件移动到容器中
1
docker cp [本地文件或目录路径] [容器名或ID]:[容器内目标路径]
docker-compose
创建镜像并启动一个容器
启动单个容器的命令很长,如果要启动多个容器来执行协调不同的任务(mysql/nginx/apache)就需要一个统筹启动的应用,docker-compose就可以解决
需要创建一个
docker-compose.yml
文件1
2
3
4
5
6
7
8
9version: "3.8"
services:
eggpain-container:
build: .
ports:
- "3000:3000"
volumes:
- ./:/egg:ro
- /egg/node_modules然后执行
1
docker-compose up -d --build
可以发现docker-compose创建了新的镜像(
nodejstest_eggpain-container_1
)和新的容器(nodejstest_eggpain-container
)如果根据已有的本地镜像文件创建一个容器(不用创建镜像)
1
docker-compose up -d #-d是静默执行
清除容器
1
2sudo docker-compose down -v
# 使用 -v 选项会删除所有与容器关联的卷,这意味着所有存储在卷中的数据将被永久删除
docker网络
如何手动关联两个容器
**Question1:**两个不同网络的docker如何通信
问题的起因是两个docker是由不同的方式启动的,一个是使用
docker run
而另一个使用docker-compose up
**Answer: **docker中提供了解决方案,直接使用命令串联两个docker
需要找出
docker-compose
启动的网卡长什么样,一般是叫做**_default
1
docker Network ls
可以轻松找到应该是
nodejstest_default
使用命令
docker network connect
1
docker network connect nodejstest_default jdk8
Bridge 网络
在安装docker之前的linux网卡信息是这样的,只有一张以太网网卡(ens33)和一张lo(loopback回环,只能和自己联通)
docker安装命令:
1 | sudo apt-get insatll docker.io -y | less |
会发现此时多了一个docker的网卡信息:
查看这张网卡的具体信息如下:
1 | sudo docker network inspect bridge | less |
使用jq来提取一些当前有用的信息:
1 | sudo docker network inspect bridge | jq '.[0] | {Name:.Name, Id:.Id, Driver:.Driver, IPAM:.IPAM.Config, Containers:.Containers, Options:.Options}' |
得到以下内容
1 | ubuntu@ubuntu:~/Desktop$ sudo docker network inspect bridge | jq '.[0] | {Name:.Name, Id:.Id, Driver:.Driver, IPAM:.IPAM.Config, Containers:.Containers, Options:.Options}' |
此时可以看到Containers
中还没有任何容器,可以添加一个功能性容器然后再来看看实力,如果本地没有这个镜像也会自动拉取
1 | sudo docker run -d --name egg1 --hostname egg1 praqma/network-multitool |
然后可以使用以下命令查看容器是否正在运行
1 | sudo docker ps |
然后再次使用命令查看网卡信息就会发现多了一个容器了
此时查看接口信息会发现多了一个奇怪的接口名称,实际上这就是使用bright的网卡情况,而且对于网卡的排序也出了问题,发现顺序为4的网卡消失了
弹幕: veth虚拟以太网接口生成了一对vethx和vethy,vethx在宿主机中与虚拟网卡docker0虚拟桥接网卡相连,vethy在容器网络命名空间内,这样实现容器进程与容器之外的外部网络通信
1 | # 需要注意的是,这个地方查看网卡信息必须使用以下命令,使用ifconfig无法查看从属关系 |
使用以下命令按json格式化网卡信息,并且输出
1 | ip -json address show dev vethd6a5d21 | jq . |
进入容器查看容器内的网卡信息
1 | sudo docker exec -it egg1 bash |
可以清晰的发现丢失的网卡4就在这里!
使用命令查询这张网卡的具体信息
1 | ip -json -detail address show dev eth0 | jq '.[0] | {ifindex:.ifindex, link_index:.link_index, ifname:.ifname, linkinfo:.linkinfo , addr_info:.addr_info}' |
可以发现对于linkinfo
这个参数,就可以判断出当前接口正在和哪个接口进行连接
同样的命令查询以太网网卡是会显示null
的
如果重新添加一个容器,也会发现这个容器有一张在宿主机中隐藏的虚拟网卡,而且这张网卡也是连接到veth
上的,然后在宿主机的网卡信息中也会发现一张指向虚拟机的虚拟网卡,也就是这个情况
Bridge型
使用命令来查看现在的网络列表
1 | sudo docker network ls |
创建bridge网络
1 | # -d使用bridge驱动来创建 |
通过查询docker network inspect
可以发现实际上两个网络的网段是不一样的
1 | sudo docker network inspect 网络名称 | jq '.[0] | {Name:.Name, Id:.Id, Driver:.Driver, IPAM:.IPAM.Config, Containers:.Containers}' |
使用命令ip address
查看网卡信息发现出现了一张新的网卡并且这个网卡名称和网卡id是一样的
现在来创建一个新容器指定使用这个网卡如下
1 | sudo docker run -d --name naihe1 --hostname naihe1 --network naihe-bridge praqma/network-multitool |
然后查看网卡信息ip address
可以发现创建了一个新的网卡使用的master网卡就是之前创建的br-9a14e1ce05d3
可以发现网卡下出现了两个容器
使用命令进去docker中的bash来ping另一个容器的ip发现是可以ping通的
1 | sudo docker exec -it naihe1 bash |
而且实际上自定义网卡还自动配置了DNS可以直接ping主机名来实现通信,但是实际上这里指定了hostname所以不明显
再创建一个容器但是不指定hostname再尝试ping看看能不能ping通
1 | sudo docker run -d --name naihe3 --network naihe-bridge praqma/network-multitool |
虚拟机死机了,重启一个停止的容器命令如下:
1 | # 查看所有容器信息 |
可以发现在没有指定容器名的前提下使用自定义网卡是可以实现自动配置dns的
删除创建的网络,但是默认的网络是没有办法删除的
1 | docker network rm naihe-bridge |
host网络型
bridge型的网络(无论是自定义还是默认)都需要手动暴露端口才能实现,使用host网络就可以避免这个问题
host网络无法自定义创建,只能有一个,会报错
1 | sudo docker network create -d host newhost |
查看网络环境发现是没有ip的
1 | docker network inspect host | jq '.[0] | {Name:.Name, Id:.Id, Driver:.Driver, IPAM:.IPAM.Config, Containers:.Containers, Options:.Options}' |
如果是指定端口关联,host模式下会出问题,因为host模式是不需要端口关联的
1 | sudo docker run --name egg --network host -p 8080:80 -d praqma/network-multitool |
发现出现警告但是仍然可以创建新的容器
实际上这个host网络下的容器就直接是宿主的一个应用了(只有linux下是这样的),在容器中与宿主设备中查看ip address
得到的网络信息是一样的