Docker#

docker img

教程手册#

好用的使用教程

Install#

略过~ 😁

基础命令#

打镜像和跑#

#

docker build -t server:v0 . -f server.dockerfile

dockerignore#

如果您想在 Dockerfile 中将当前目录中的所有文件都复制到 Docker 镜像中,可以使用 Dockerfile 中的 COPY 指令。具体的语法如下:

COPY . /目标路径/

其中. 表示当前目录,/目标路径/ 表示目标路径,这里可以是绝对路径或相对路径。 这将会将当前目录中的所有文件复制到镜像中的 /app/ 目录下。请注意,在这种情况下,所有文件和文件夹都会被复制到镜像中,包括隐藏文件和文件夹。如果您不想复制某些文件或文件夹,可以在运行 COPY 指令之前通过 .dockerignore 文件来指定忽略的文件和文件夹。

#

docker run -p 9080:80 --name server server:v0

指定启动命令#

sudo docker run -it -p 9080:80 --name nova_server nova_server:v0 sh -c "echo hello"

加入自定义网络#

--network {{network name}} 详见:[[#Network]]

跑出问题-进入容器排查#

sudo docker run -it -p 9080:80 --name nova_server nova_server:v0 sh -c "bash"

使用-it进入容器手动执行命令进行调试

启动全部容器#

docker ps -a | grep "Exited" | awk '{print $1}' | xargs docker start

重命名#

podman rename {old_name} {new_name}

清理Docker占用空间#

好的,您遇到的 /var/lib/docker 目录空间不足是一个非常常见的问题,尤其是 containersoverlay2 目录。清理的原则是:清理无用的数据,保留正在运行容器所需的数据。

请按照以下步骤安全操作,这些命令旨在清理不再使用的资源,不会影响正在运行的服务。


第零步:首要建议(如果可用)#

最安全、影响最小的方法是清理整个Docker系统的无用资源,这是一个汇总命令,会清理所有悬空镜像、容器、网络和构建缓存:

docker system prune -a
# 或者 docker system prune -a --volumes   (这个会清理未使用的卷,**更彻底但请谨慎,确保卷确实无用**)

注意-a 会删除所有未被容器使用的镜像(而不仅仅是悬空镜像),所以如果你有一些暂时停用的镜像也会被删掉。执行前它会列出要删除的内容并请求确认。

如果 docker system prune 后空间仍然不足,再继续下面的针对性清理。


异常磁盘占用#

第一步:清理容器日志(这是 /var/lib/docker/containers 巨大的首要元凶)#

容器日志文件会持续增长,是占用 containers 目录空间的罪魁祸首。

1. 查找大日志文件:

# 查找大于100M的日志文件
find /var/lib/docker/containers/ -name "*.log" -size +100M

2. 安全清理方法(推荐): 对于正在运行的容器,直接删除其日志文件可能会导致 docker logs 命令无法查看历史日志,但更安全的方法是重置日志文件

# 方法A:逐个容器清理(最安全)
# 首先获取容器ID和名称
docker ps --format "table {{.ID}}\t{{.Names}}"

# 假设你想清理名为 'my-app' 的容器的日志
truncate -s 0 /var/lib/docker/containers/$(docker inspect --format='{{.Id}}' my-app)/*-json.log

# 方法B:批量清理所有容器的日志(会影响所有容器的历史日志)
find /var/lib/docker/containers/ -name "*.log" -exec truncate -s 0 {} \;

truncate -s 0 命令会将文件大小截断为0,但文件描述符仍被进程持有,这样容器可以继续写入新日志,而不会报错或需要重启。

3. 根本解决方法(配置日志轮转): 为了防止未来再次出现此问题,必须在 /etc/docker/daemon.json 中为容器配置日志驱动和轮转策略:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

修改后需要重启 Docker 服务:sudo systemctl restart docker这只会对新创建的容器生效,现有容器需要重建。


第二步:清理 Overlay2 文件系统(这是 /var/lib/docker/overlay2 巨大的原因)#

overlay2 目录存放的是镜像层、容器可写层等。清理的核心是删除不再使用的镜像和容器

1. 删除所有已停止的容器:

docker container prune
# 或者强制删除所有已停止的容器(更彻底)
docker rm $(docker ps -aq)

2. 删除所有悬空镜像(那些没有被任何镜像引用的中间层):

docker image prune

3. 删除所有未被使用的镜像和容器(包括被停止的容器使用的镜像):

docker system prune -a

4. 谨慎操作:删除未被任何容器引用的卷(Volume): 卷通常存放重要数据(如数据库数据),请务必确认这些卷不再需要!

docker volume prune

第三步:检查并清理 Docker 构建缓存#

如果你经常使用 docker build,构建缓存也会占用大量空间。

docker builder prune

总结与安全操作流程#

为了不影响服务,请按以下顺序操作:

  1. 清理日志:使用 truncate 命令安全地清理大日志文件。
    find /var/lib/docker/containers/ -name "*.log" -size +100M -exec truncate -s 0 {} \;
  2. 清理停止的容器
    docker container prune
  3. 清理悬空镜像
    docker image prune
  4. 如果空间仍然不足,执行更彻底的清理
    docker system prune -a
  5. 最后,配置日志轮转:编辑 /etc/docker/daemon.json 并重启 Docker,这是长治久安之策。

重要提示:在执行任何 prune 命令前,系统都会列出将要删除的项目并请求确认。请仔细阅读确认列表,确保没有误删重要资源。按照这个流程,你可以安全地回收数十GB的空间,而不会影响到正在运行的容器服务。

Network#

  1. docker run时容器加入方法-redis为例
  2. 后期加入方式
  3. 创建一个新网
  4. 检测
    init_redis:
    	docker run -p 6379:6379 \\
    	--network websafe-network \\
	    	--name redislatest redis:latest --requirepass 3b21d032a7fd8eb51fa7bd8a2e812b78b7b3a36f 
    
    join_network:
    	docker network connect websafe-network mysql56
    	docker network connect websafe-network daemon-xxx
    
    init_network:
    	docker network create websafe-network
    
    check_network:
    	docker network inspect websafe-network
    	docker network inspect websafe-network | findStr IPv4Address
    

删除#

lazydocker 可视化#

go install github.com/jesseduffield/lazydocker@latest

如果需要sudo权限的话无法直接执行命令,只能where获取原始路径后sudo+原始路径执行 如:

  • sudo /home/ian/go/bin/lazydocker
  • sudo lazydocker

常见问题和模板#

用户sudo问题#

debian增加docker用户组,优化每次sudo问题

sudo groupadd docker # 安装完docker.io之后一般都会自动创建所以这一步其实没啥用
sudo gpasswd -a $USERNAME docker
newgrp docker # 更新

不好使的话#

这里我有个docker(Docker version 24.0.5, build ced0996)

docker --version
sudo groupadd docker
sudo gpasswd -a ian docker
sudo systemctl status snap.docker.dockerd.service
sudo systemctl restart snap.docker.dockerd.service
sudo systemctl status snap.docker.dockerd.service
sudo usermod -aG docker ian
sudo chmod 666 /var/run/docker.sock
sudo setfacl --modify user:ian:rw /var/run/docker.sock
docker ps -a

Docker Mysql编码#

version: "2.2"
services:
  redis:
    image: "redis"
    # ports:
    #  - 6379:6379
    command: redis-server --appendonly yes #一个容器启动时要运行的命令
    restart: always # 自动重启
  myserver:
    image: mainName/myserver
    restart: always # 自动重启
  mainServer:
    image: mainName/mainServer
    #    container_name: mainServerv1.0.0
    depends_on:
      - redis
    ports:
      - 9001:9001
    restart: always
    volumes:
      - "./logs:/src/build/logs"
    links:
      - redis
      - myserver

mysql 编码问题|单条#

docker run --name predix_mysql -e MYSQL_ROOT_PASSWORD=predix123predix -p 33061:3306  -e LANG=C.UTF-8 -e TZ=Asia/Shanghai -d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci`

时区修改-镜像时间问题#

FROM alpine:3.14
RUN apk add -U tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime &&  echo "Asia/Shanghai" > /etc/timezone

ENV TZ=Asia/Shanghai \
    GO111MODULE=on \
    CGO_ENABLED=0 \
    GOOS=linux \
    GOARCH=amd64 \
    PROGRAM_ENV=pro

WORKDIR /src/build

# 复制构建应用程序所需的代码
COPY ./build .

EXPOSE 8088

CMD ["./main"]

Mysql 时区问题#

-e TZ=Asia/Shanghai

bash进入某App内#

docker exec -it webserver bash

webserver 为APP名称

Swarm#

Docker Compose Docker Machine: Mac、Windows区别预先安装。 Linux直接安装 Win10 Hyper-V 发布镜像 镜像充当已部署容器,填写必要信息:username、repo、tag dockers-compose.yml 副本

其实以上在官方教程有很好说明在这里,但毕竟高级应用,暂且记下。

创建虚拟机来试验一下#

$ docker-machine create --driver virtualbox myvm1
$ docker-machine create --driver virtualbox myvm2

第一个管理节点:docker swarm init,第二个工作节点`docker swarm join``

should like this show:#
$ docker-machine ssh myvm1 "docker swarm init"
Swarm initialized: current node <node ID> is now a manager.

To add a worker to this swarm, run the following command:

  docker swarm join \
  --token <token> \
  <ip>:<port>

通过运行 docker-machine ls 来复制 myvm1 的 IP 地址,然后使用 该 IP 地址并通过 –advertise-addr 指定端口 2377(用于 swarm join 的端口), 以便再次运行 docker swarm init 命令。例如:

    docker-machine ssh myvm1 "docker swarm init --advertise-addr 192.168.99.100:2377"
复制此命令,然后通过 docker-machine ssh 将其发送给 myvm2,从而让 myvm2 加入#
$ docker-machine ssh myvm2 "docker swarm join \
--token <token> \
<ip>:<port>"

This node joined a swarm as a worker.

至此, 创建swarm完成。

空间占用问题#

  • 首先查看docker存储位置
sudo docker info
# 这里: Docker Root Dir:

修改/etc/docker/deamon.json or ~/.config/docker/daemon.json: { "data-root": "/home/hellxz/docker-home"}

通过snap安装的docker配置文件路径#

  • /var/snap/docker/current/etc/docker/daemon.json
  • /var/snap/docker/current/config/daemon.json
sudo snap restart docker

连接#

使用ssh连接docker-machine ssh myvm1,运行docker node ls查看此中节点。

Mybe like this.#

docker@myvm1:~$ docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
brtu9urxwfd5j0zrmkubhpkbd     myvm2               Ready               Active              
rihwohkh3ph38fhillhhb84sk *   myvm1               Ready               Active              Leader

mybe not you are ture. 😂

之后,其余东西z有用到再去官网查看吧。 记录与否,取决于俺。

supervisord 禁用日志文件或使用logfile=/dev/stdout#

from: https://www.coder.work/article/100835 标签 docker supervisord

[supervisord]
nodaemon=true
logfile=/dev/stdout
pidfile=/var/run/supervisord.pid
childlogdir=/var/log/supervisor

当我这样做时,这个主管会崩溃,因为它无法在/dev/stdout 中寻找

如何禁用 supervisord 在我的 docker 容器中创建任何日志文件?

最佳答案

对于主主管,nodaemon 将导致日志转到 stdout

[supervisord]
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0

然后将每个托管进程的日志发送到标准输出文件描述符/dev/fd/1

[program:x]
command=echo test
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true

或者,如果您希望将 stderr 保留在不同的流上:

[program:x]
command=echo test
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
stderr_logfile=/dev/fd/2
stderr_logfile_maxbytes=0

关于docker - supervisord 禁用日志文件或使用 logfile=/dev/stdout,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45645758/

sed报Device or resource busy错误的处理原因及方式#

转载 kuSorZ 博主文章分类:Linux 文章标签: docker | sed 文章分类: Docker 原文出处: https://www.cnblogs.com/xuxinkun/p/7116737.html错误现象

在docker容器中想要修改/etc/resolv.conf中的namesever,使用sed命令进行执行时遇到错误:

/ # sed -i ’s/192.168.1.1/192.168.1.254/g’ /etc/resolv.conf sed: can’t move ‘/etc/resolv.conf73UqmG’ to ‘/etc/resolv.conf’: Device or resource busy

但是可以通过vi/vim直接修改这个文件/etc/resolv.conf这个文件的内容。 问题原因

sed命令的实质并不是修改文件,而是产生一个新的文件替换原有的文件。这里我们做了一个实验。

我先创建了一个test.txt的文件,文件内容是123。然后我使用sed命令对文件内容进行了替换。再次查看test.txt。

/ # stat test.txt File: test.txt Size: 4 Blocks: 8 IO Block: 4096 regular fileDevice: fd28h/64808d Inode: 265 Links: 1Access: (0644/-rw-r–r–) Uid: ( 0/ root) Gid: ( 0/ root)Access: 2017-07-04 06:28:35.000000000Modify: 2017-07-04 06:28:17.000000000Change: 2017-07-04 06:29:03.000000000/ # cat test.txt 123/ # sed -i ’s/123/321/g’ test.txt/ # stat test.txt File: test.txt Size: 4 Blocks: 8 IO Block: 4096 regular fileDevice: fd28h/64808d Inode: 266 Links: 1Access: (0644/-rw-r–r–) Uid: ( 0/ root) Gid: ( 0/ root)Access: 2017-07-04 06:29:31.000000000Modify: 2017-07-04 06:29:31.000000000Change: 2017-07-04 06:29:31.000000000/ # cat test.txt321

可以看到文件内容被正确修改了,但是同时,文件的inode也修改了。说明了实质上是新生成的文件替换了原有的文件。但是vim/vi是在原文件基础上修改的,所以inode没有变化。

在docker中,/etc/resolv.conf是通过挂载入容器的。所以当你想去删除这个挂载文件,也就是挂载点时,自然就会报Device or resource busy。

这个跟是不是特权privilege没有关系。即使是privilege的容器,也会有这个问题。 / # rm /etc/resolv.conf rm: can’t remove ‘/etc/resolv.conf’: Device or resource busy

其实不仅仅/etc/resolv.conf,还有/etc/hostname,/etc/hosts等文件都是通过挂载方式挂载到容器中来的。所以想要用sed对他们进行修改,都会遇到这样的问题。我们可以通过df -h查看容器内的挂载情况。

/ # df -h Filesystem Size Used Available Use% Mounted on/dev/mapper/docker-253:2-807144231-37acfcd86387ddcbc52ef8dac69d919283fc5d9d8ab5f55fd23d1c782e3b1c70 10.0G 33.8M 10.0G 0% /tmpfs 15.4G 0 15.4G 0% /devtmpfs 15.4G 0 15.4G 0% /sys/fs/cgroup/dev/mapper/centos-home 212.1G 181.8G 30.3G 86% /run/secrets/dev/mapper/centos-home 212.1G 181.8G 30.3G 86% /dev/termination-log/dev/mapper/centos-home 212.1G 181.8G 30.3G 86% /etc/resolv.conf/dev/mapper/centos-home 212.1G 181.8G 30.3G 86% /etc/hostname/dev/mapper/centos-home 212.1G 181.8G 30.3G 86% /etc/hostsshm 64.0M 0 64.0M 0% /dev/shmtmpfs 15.4G 0 15.4G 0% /proc/kcoretmpfs 15.4G 0 15.4G 0% /proc/timer_stats

如何解决

使用vi固然可以,但是对于批量操作就不是很合适了。可以通过sed和echo的组合命令echo “$(sed ’s/192.168.1.1/192.168.1.254/g’ /etc/resolv.conf)” > /etc/resolv.conf 即可实现替换。

/ # cat /etc/resolv.conf search default.svc.games.local svc.games.local games.localnameserver 192.168.1.1options ndots:5/ # echo “$(sed ’s/192.168.1.1/192.168.1.254/g’ /etc/resolv.conf)” > /etc/resolv.conf / # cat /etc/resolv.conf search default.svc.games.local svc.games.local games.localnameserver 192.168.1.254options ndots:5

这里如果使用sed ’s/192.168.1.1/192.168.1.254/g’ /etc/resolv.conf > /etc/resolv.conf是无效的。最终会导致/etc/resolv.conf内容为空。

示例#

Dockerfile#

CMD mkdir -p /var/log/scancenter \
    && sed 's/INFO\|ERROR/DEBUG/g' -i scancenter/logging.cfg \
    && uwsgi /opt/disk2/var/www/scancenter/3rd/conf/uwsgi-docker/uwsgi.ini --log-master

k8s yaml#

    spec:
      containers:
      - command:
        - /bin/sh
        - -c
        - mkdir -p /var/log/scancenter &&
          echo -e "10.120.16.12\tapi.s.com\n10.5.25.5\tpp.api.com" >> /etc/hosts &&
          echo "$(sed 's/^-e //g' /etc/hosts)" > /etc/hosts &&
          sed 's/INFO\|ERROR/DEBUG/g' -i scancenter/logging.cfg &&
          uwsgi /opt/disk2/var/www/scancenter/3rd/conf/uwsgi-docker/uwsgi.ini
        env:
        - name: POD_IP_ADDRESS
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: status.podIP