一、前言 docker是一个将软件虚拟化的工具,可以在任意设备上,建立虚拟机跑软件,实现快速环境搭建运行
二、安装 自行百度,不造轮子了
三、配置 1. docker的默认网段 修改/etc/docker/daemon.json
默认的网段是172.17.0.0/12
,size是16。代表分配的网桥段是172.[17-31].0.0/16
下面配置代表新建立的网桥分配段为172.31.[0-255].0/24
例如: 网桥1 172.22.31.1.0/24
,网桥2 172.22.31.2.0/24
1 2 3 4 5 6 7 8 { "default-address-pools" : [ { "base" : "172.31.0.0/16" , "size" : 24 } ] }
注意 已经建立好的网桥不会清除,需要停止容器,删除对应网桥重新起容器绑定新的才可以 2. docker的网络模式 host: 不生成虚拟网卡和ip,使用宿主机的网络,无法使用端口映射 container: 和另一个容器共享ip和端口,compose配置network_mode: "container:[container name/id]"
none: 关闭容器网络功能,容器无法联网 bridge: 创建一个网桥,虚拟出网卡和ip,通过docker0和iptables配置和主机通信 service: compose的概念,和service共享网络,配置network_mode: "service:[service name]"
四、常用命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 # # 查看所有容器 docker ps -a # 停止容器 docker stop [container_id] # 删除container docker rm [container_id] # 将某个容器变成自启动 docker update [container_id] --restart=always # 拷贝文件 docker cp [OPTIONS] [container_id]:[SRC_PATH] [DEST_PATH] docker cp [OPTIONS] [SRC_PATH] [container_id]:[DEST_PATH] # # 列出所有image docker image list # 导入一个image docker load -i [image_file] # 导出一个image,使用image_id打包后导入名字会变成none docker save [image_id|image_name:tag] -o xxx.tar # 删除image docker rmi [image_id] # 重命名image docker tag [image_id] xxx # # 查看docker日志 # -f : 跟踪日志输出 # --since : 显示某个开始时间的所有日志 # -t : 显示时间戳 # --tail :仅列出最新N条容器日志 docker logs [OPTIONS] [container_name|container_id]
1. docker top 查看docker和宿主机的进程对照关系 1 2 3 4 5 # PID是宿主机进程id ,PPID是docker里面的id => docker top [container_name|container_id] UID PID PPID C STIME TTY TIME CMD nobody 26505 26486 0 2月16 ? 00:02:53 /usr/bin/python3.6 /usr/bin/supervisord -nc /etc/supervisord.conf nobody 26560 26505 0 2月16 ? 00:00:00 npm
2. docker network 查看docker网络情况 1 2 3 4 5 6 7 => docker network list NETWORK ID NAME DRIVER SCOPE f5efcaf6e2e2 bridge bridge local 237ebc86fb1b host host local d082a187db55 none null local # 删除一个网络,最好先停止容器,再删除网络 => docker network rm [network_id]
3. docker search 搜索镜像 1 2 3 4 5 6 7 => docker search kali NAME DESCRIPTION STARS OFFICIAL AUTOMATED kalilinux/kali-rolling Official Kali Linux Docker image (weekly sna… 786 kasmweb/kali-rolling-desktop Kali Rolling desktop for Kasm Workspaces 11 kalilinux/kali-bleeding-edge Same as kali-rolling with kali-bleeding-edge… 52 kalilinux/kali-last-release Image built from the last snapshot of the of… 55 ...
4. docker run 启动镜像 1 docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
4.1. 选项 1) 常用选项 -d
: 后台运行-p [host-port:docker-port]
: 端口映射--rm
: 停止后删除容器--name [name]
: 给容器起名字--network [network-mode]
: 网络模式,也可以指定自己建立的网络-i
: 启动后无需命令也不停止,就是compose的tty为true-v [host-dir:docker-dir]
: 目录映射--restart=always
: 开机自启动-e [xxx=val]
: 设置环境变量示例
1 2 3 4 5 # 启动一个image # -d 后台运行 # -p host:docker 端口映射 # --rm 容器停止后删除容器 docker run -d -p 8085:8080 [image_name]:[tag]
2) cpu限制 --cpus=<value>
: 限制cpu核心数,--cpus='1.5'
代表使用一个半核--cpuset-cpus
: 限制使用特定的cpu,0-3
代表前4个核,1,3
代表第二个和第4个--cpu-period
: 设置每个容器进程的调度周期(CFS)下,范围1000-1000000
对应单位us--cpu-quota
: 设置每个周期内容器能使用的cpu时间,和--cpu-period
配合使用,quota大于period代表使用多个核,不能小于1000示例
1 2 3 4 5 6 7 8 9 # 最大使用1.5个核 docker run -d golang:latest --cpus=1.5 # 限制使用0、2、3这三个核 docker run -d golang:latest --cpuset-cpus=0,2-3 # docker进程调度周期为50ms,每个周期docker使用25ms的cpu,也就是最多占用0.5个核 # quota大于period代表使用多个核 docker run -d golang:latest --cpu-period=50000 --cpu-quota=25000
3) 内存限制 -m
: 指定内存使用限额,如200M--memory-swap
: 设置内存+swap的限额,默认为-m
的两倍,也就是内存和swap相同4) 启动后不退出 (1) 使用tail
命令不退出 1 docker run xxx tail -f /dev/null
(2) 使用sleep
命令不退出 1 docker run xxx sleep infinity
五、docker-compose.yml
解释和编写 1. 基础用法示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 version: '3' services: sms_server: container_name: sms_server image: 'node:latest' ports: - "7878:7878" volumes: - .:/code:ro network_mode: "bridge" environment: MYSQL_ROOT_PASSWORD: "123456" GO111MODULE: 'on' GOPROXY: 'https://goproxy.cn' working_dir: /code command: ["node" , "server.js" ] restart: always privileged: false cap_add: - ALL cap_drop: - NET_ADMIN - SYS_ADMIN
2. service和container service是docker-compose的概念,container是docker的概念 一个service可以存在多个container,对应到docker ps
就是多个container,docker ps
无法查看service的名字 同一个service下面可以起多个相同的容器docker-compose up --scale sms_server=5
不能指定container_name
,指定就无法起,默认使用<当前路径名>_<service name>_<序号>
起名 如果指定了端口映射,这里也会报错,因为端口被占用 3. cpu限制 services.<server_name>.deploy.resources.limits.cpus
和docker run的--cpus
对应,具体含义见上面解释1 2 3 4 5 6 7 8 9 10 11 12 13 version: '3' services: other-compile: container_name: other-compile image: 'cicd_2601/package-env:go1.20.2' deploy: resources: limits: cpus: 4 network_mode: 'host' tty: true privileged: false restart: always
六、实战 1. 启用一个sms_server
服务 根据一个实例可以快速上手
1.1. 需求 将一个nodejs实现的服务器部署到docker上 代码在服务器硬盘,可以实现修改了代码,重启一个服务就可以生效 1.2. 服务器代码 很简单的一个监听7878端口http请求,统一返回一个json的设置cookie的代码,运行也只需要node server.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const http = require ("http" );const url = require ("url" );let json = { "code" : "0" , "llll" : "test" , "aaaa" : "stest" , "token" : "a454as1bbvd5g5s15155" } let index = 0 ;http.createServer (function (req, res ) { res.setHeader ("Set-Cookie" , ["c=1;httponly" , "b=2" , "a=3" ]); res.writeHead (200 , { "Content-Type" : "application/json" , "Content-Length" : Buffer .from (JSON .stringify (json)).length }) res.write (JSON .stringify (json)) index++ console .log (`<h3>${index} </h3>` ) req.on ("data" , function (chunk ) { console .log (chunk.toString ()) }) res.end () }).listen (7878 , "0.0.0.0" ) console .log ("the server is starting" );
1.3. 编写docker-compose.yml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 version: '3' services: sms_server: container_name: sms_server image: 'node:latest' ports: - "7878:7878" volumes: - .:/code:ro network_mode: "bridge" working_dir: /code command: ["node" , "server.js" ] restart: always
1.4. 运行 1 2 3 # 指定yml文件,-d后台运行 # --force-recreate 强制重建 sudo docker-compose -f server.yml up -d
2. 使用mysql 2.1. 安装 1 docker pull mysql:latest
2.2. 运行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 version: '3' services: mysql: container_name: mysql image: 'mysql:latest' volumes: - ./data/var_lib_mysql:/var/lib/mysql:rw ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: "123456" tty: true restart: always
3. 构建deepin开发环境 基于镜像168447636/deepin20
3.1. 初始化设置 1 2 3 4 5 6 7 # 安装必备软件 apt install zsh tmux git gdb iptables net-tools dnsutils apt-file locales wget curl iputils-ping apt autoremove # 更新apt-file apt-file update # 设置时区 ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
1 docker commit deepin_worker deepin_worker
3.2. docker-compose.yml编写 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 version: '3' services: deepin_worker: container_name: deepin_worker image: 'deepin_worker:latest' network_mode: 'bridge' volumes: - .:/code:rw environment: GO111MODULE: 'on' GOPROXY: 'http://goproxy.cn' GOSUMDB: 'off' working_dir: /code tty: true privileged: true restart: always
七、源码阅读 1. docker各个组件之间的关系 小技巧和踩坑记 1. docker容器内部无法使用iptables命令 容器本身是跟操作系统绑定,并非完整的系统,所以iptables其实操作的是宿主机的 如果是编译环境做测试用的,可以直接加上--privileged
或--add-cap NET_ADMIN
2. docker pull报错Error: remote trust data does not exist for xxx
明确是信任的镜像,加上DOCKER_CONTENT_TRUST=false
运行即可
1 DOCKER_CONTENT_TRUST=false docker pull xxx
3. docker修改镜像和容器存储目录 docker的默认目录在/var/lib/docker
,如果根目录分配比较小的情况下会导致根目录占满
1 2 => docker info | grep -i root Docker Root Dir: /var/lib/docker
修改此目录按照下面的命令执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # 先停止docker服务 => systemctl stop docker docker.socket # 拷贝到新目录 => cp -r /var/lib/docker /path/to/new # 修改docker配置文件 => vim /etc/docker/daemon.json # 修改如下内容 # { # "data-root" : "/path/to/new" # } # 重启docker即可 => systemctl start docker # 老的目录删掉 => rm -rf /var/lib/docker
和上面第2点是一样的,都是不信任导致,临时规避方式一样
1 DOCKER_CONTENT_TRUST=0 docker run xxx