Server搭建过程-9.Docker个人心得
1.Docker的基本使用
参考链接:
1.40分钟的Docker实战攻略,一期视频精通Docker
2.Docker概念,工作流和实践 - 入门必懂
3.Docker — 从入门到实践
在Docker还没有出现的时期,使用裸机直接部署软件服务。
软件运行总要基于一些环境,而每个软件需要的环境配置可能各不相同。
先不说配环境有多痛苦,甚至有些软件需要同一个环境的不同版本,会引起冲突。
而且迁移方面,你的设备上也许能正常运行这个软件服务,别的设备上由于环境变化,软件服务就有可能运行不了了。
因此很自然的想出虚拟化的方案,先把软件服务需要的环境和软件一起打包,运行在一个独立的虚拟化环境,方便软件的部署和迁移。
但传统的虚拟化,是直接模拟出一套完整的硬件和一套完整的操作系统内核。
对于部署软件来说,很多时候都不需要这么完整的虚拟化,同时这种虚拟化的性能开销太大。
Linux内核支持操作系统层面的虚拟化技术。(这基于cgroup
, namespace
等特性)
在这基础上,docker做到了每个虚拟的容器,共用同一个系统内核(也就是宿主机的内核。)
同时docker也没有进行硬件的虚拟,而是直接使用宿主机的硬件。
运行的每个容器,就像是宿主机下一个一个的独立进程。
相较于传统的虚拟化大大降低了性能开销,同时这种虚拟化的结构更加短小精悍。
虽然说共用宿主机的系统内核,但你可能发现不同容器内的Linux发行版不同。
其实这只代表了用户空间,实际上还是同一个宿主机内核。
总结来讲,Docker有几个好处:
1.性能损耗低,资源利用率高,比传统虚拟化高效得多。(一般来说性能表现接近原生)
2.开箱即用,上手简单,镜像生态好(通过编写Dockerfile
或者拿到别人预先构建好的镜像,可以快速部署直接可用的服务)
3.提供了一致的运行环境,打包迁移容器和镜像方便、快速。
4.每个容器之间独立隔离开来,既保证了容器内运行服务不受干扰,也一定程度上保障了安全。
Docker有两个概念,一个是镜像一个是容器。
镜像类似于模板,事先定义好了一套完整的应用程序运行环境,包括代码、库、依赖和配置。
而容器其实就是基于镜像所创建的一个具象的实例。像是根据图纸来构建出真正的房子。
可能听起来比较难理解,不过真正使用起来应该就马上懂了。
关于镜像和容器有几点需要注意的:
容器和镜像都是采用了分层存储的结构。容器实际上是在镜像的基础上,创建了一层可写层。
为了避免镜像间引用的依赖链过长和虚悬镜像。不要把生成的容器再次构建成镜像,接着循序反复。
建议直接使用Dockerfile,一次性安装完所有所需依赖,直接构建成一个镜像,减少中间层。
同时尽量保持可写层的无状态性,容器内使用数据卷或者绑定宿主目录。
对于分层存储,目前需要理解的就这么多。
更多深入内容等到初学之后,想自己编写Dockerfile
时再查看。
1.docker pull
完整的命令示例:
1 | docker pull docker.io/library/nginx:latest |
几个参数介绍:docker.io
:默认对应Docker Hub
官方仓库地址,也可以替换为其他仓库地址(例如国内的一些镜像源)。library
:默认对应官方镜像的命名空间,相当于作者名。镜像冒号后的部分
:用于指定镜像的标签(tag
),常用来表示版本号(如nginx:1.25
),默认值为latest
。意为最新版本。
1 | docker pull nginx |
表示:在Docker官方仓库的官方命名空间内,下载Nginx的最新版本。
1 | docker pull cloudreve/cloudreve |
表示:在Docker官方仓库的Cloudreve
作者名,下载Cloudreve
的最新版本。
1 | docker pull docker.xuanyuan.me/mysql |
表示:在docker.xuanyuan.me
这个非官方仓库的官方命名空间内,下载mysql
的最新版本。
这也是一种临时换源的办法,把仓库地址指定为国内的镜像源。
2.docker images(等同于docker image ls
)
列出本地所存的镜像。
1 | REPOSITORY TAG IMAGE ID CREATED SIZE |
3.docker tag
上面docker images
中,经过临时代理下载的镜像,REPOSITORY
名变得比官方仓库的长的多。
想要重命名镜像,可以使用docker tag
命令。
1 | docker tag docker.m.daocloud.io/node node |
和上面类似的,如果镜像名后不写tag
,默认为latest
。
需要注意:tag
命令只是新增了一个标签指向这个镜像。
现在其实node:latest
和 docker.m.daocloud.io/node:latest
这两个tag
都指向了同一镜像。(即IMAGE ID
为0c7eb8906f06
的镜像)需要的话,可以使用命令把原来的长tag
删除。
1 | docker rmi docker.m.daocloud.io/node |
实际上执行命令后,Docker
首先会把这个tag
删除。如果还有其他tag
指向同一个镜像ID,那镜像文件还会保留。
当这个镜像的所有tag
都没了,且没有容器依赖它,这个镜像ID就会真正从磁盘上清出。
4.docker run
常规命令
1 | docker run --network host --name atest -itd nginx |
docker start/stop/restart
docker ps
ps中,容器的启动命令是在哪里编写的,Dockerfile吗?
ps中,容器的启动命令中的当前终端(比如sh、bash)如何进入。
docker run中指定 -arg代理变量是如何在容器内生效的?指定在某个终端(比如sh和bash)生效吗?
docker log 中记录的容器日志是从哪来的,终端输出的信息吗?
docker ps -a
docker rename
docker exec
我们都知道,使用
1 | docker exec -it node bash |
的话,打开top
监视,会发现创建了一个新的bash终端。
这也正是linux的特性,用户可以同时打开并独立操作多个终端,而互不影响。
docker copy
docker build
docker push
docker rm/rmi
先说说使用docker镜像
搭建tailscale
的derp
中转服务器。
参考链接:
1.https://icloudnative.io/posts/custom-derp-servers/#使用纯-ip
2.https://github.com/yangchuansheng/ip_derper
3.https://blog.csdn.net/god_sword_/article/details/129353427
4.https://neucrack.com/p/286
5.令人头疼的 docker 代理问题,我整理了解决方法和验证方案
docker需要换源和代理的,修改这里:
1 | vim /etc/docker/daemon.json |
格式类似这样:
1 | { |
如果只是调整json文件而没有更改systemd的配置文件,只需要重启docker就行了。
1 | sudo systemctl restart docker |
否则,则输入这两条命令让配置生效。
1 | sudo systemctl daemon-reload |
若要检查生效情况,可以执行docker info
在信息中有http proxy等字眼就是成功了。
配置后拉取镜像可能一开始会EOF报错,多拉几次就好了。
docker pull和 push都可以用这个。
当然一般来说设置了代理就不设置国内镜像源,设置了国内镜像源就不设置代理。
因为两个都设置的情况下,就是在国内镜像源内寻找镜像,接着通过代理拉取到本地,纯粹没必要这样做。
一般情况下我不设置国内镜像源,因为国内镜像源并不稳定,哪天没了还得再找。
以下都以代理配置为主。
设置了可用的国内镜像源,等效于daemon.json+宿主机终端代理设置。
docker build又分两种情况,第一种是docker deamon pull外部镜像,比如用FROM go等别的镜像,
第二种情况是构建的临时容器内 如wget下载github文件等可能。
检查daemon.json是否对两种有用,可以用curl然后docker查看容器日志的形式。
另外检查daemon.json是否能直接使得容器内挂在代理上,额是不是受了itd后台运行的影响,不开后台d 用原本的终端程序进去看看有没有代理。
另外有一种情况,服务器开启了公网ipv6的地址(比如腾讯云的服务器),而一般的代理工具只代理V4。
docker build拉取镜像的时候报错信息里面有IPV6的地址,应该就是daemon优先使用了v6地址。
因此daemon这样设置:
1 | { |
docker build的时候会终端
不要pull再build
daemon不会影响buld
config.json对应传进去容器内
network了就不用再config,network能直接终端,不需要再config设置。和run后打开的容器不一样。
docker build 时候From镜像的部分,也就是这部分:
1 | => [internal] load build definition from Dockerfile |
如果国内环境,什么也不动的情况下,大概率是在load metadata这一行就会卡住。
Build分两部分:
FROM 镜像,load metadata这些部分应该算是dockerd的,因为这部分只需要在配置好daemon.json的前提下
(记得docker info检查一下json配置文件生效没)
将宿主机的终端设置上代理变量,就可以正常通过FROM这一关。
1 | export http_proxy=http://127.0.0.1:7890 |
当然你如果不是裸核运行,有自动化的工具已经帮你配好变量的话就不用弄这一步了。
另一部分就是build后开启的临时容器,这其中会执行Dockerfile
中RUN等各种参数。
docker run 添加--network host
参数已经起不了作用了,并不能使得临时容器内成功使用到宿主机的代理。
要么在docker run
中使用--build-arg
参数,要么在~/.docker/config.json
配置文件下设置代理。
都能把代理变量传入临时容器中。
至于代理变量的值是多少,要看你docker run添不添加--network host
参数
加了的话就127.0.0.1,不加就是docker的虚拟网址。
参考:
1 | docker build \ |
一般来说上面虽然export了很多变量在终端,但是docker容器内部一般来说用不到socks和noproxy吧?
根据自己情况来调整最好。
我选择cd到opt目录下编译文件。
1 | cd /opt |
先把相关文件git下来
1 | git clone https://github.com/yangchuansheng/ip_derper |
里面有参考链接1对应的生成证书sh脚本和Dockerfile。
cd到git下载的文件夹内,即和build_cert.sh
、Dockerfile
的同级目录下:
1 | cd ip_derper |
接着git clone tailscale上的官方仓库
1 | git clone https://github.com/tailscale/tailscale |
因为Dockerfile里面写的是ADD变量,要把宿主机上的tailscale对应文件复制进docker容器编译。所以先要把文件下到宿主机。
更改cert.go文件以支持纯IP
1 | vim tailscale/cmd/derper/cert.go |
找到这三行:(大概在第131行)
1 | if hi.ServerName != m.hostname && !m.noHostname { |
删除或者注释掉。
回到Dockerfile
目录下
1 | cd /opt/ip_derper |
使用docker
构建镜像
1 | docker build --network host -t derp . |
之前在daemon.json设置了换源和代理,build的时候其实会开一个临时容器,build的时候设置网络模式为host,直接用宿主机的7890代理端口,加快编译。
(到时候记得测试一下docker exec进容器终端能不能用代理)
~./docker/config.json和/etc/docker/daemon.json这两个设置代理的区别。
1 | docker run --network host --name derp -itd derp |