docker 使用中的重点总结【长期更新】

记录日常使用中 docker 遇到的一些问题。

docker篇

记录备忘关于docker 的一些要点难点。

快速安装docker-ce

docker 下载链接:
https://download.docker.com/linux/static/stable/x86_64/

解压:
tar xf docker-20.10.9.tgz

拷贝命令到指定目录:
cp -a * /usr/bin/

开启转发数据包
cat << 'EOF' >> /etc/sysctl.conf
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF

sysctl --system

编写docker配置:
mkdir /etc/docker
cat << 'EOF' > /etc/docker/daemon.json
{
  "log-driver": "json-file",
  "data-root": "/data/docker",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  },
  "exec-opts": ["native.cgroupdriver=systemd"],
  "storage-driver": "overlay2",
  "storage-opts": [
    "overlay2.override_kernel_check=true"
  ],
  "insecure-registries": [
    "192.168.1.200:80"
  ],
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com"
  ]
}
EOF

添加启动脚本:
cat << EOF > /usr/lib/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target

[Service]
Type=notify
the default is not to use systemd for cgroups because the delegate issues still
exists and systemd currently does not support the cgroup feature set required
for containers run by docker
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP
TimeoutSec=0
RestartSec=2
Restart=always

Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229.

Both the old, and new location are accepted by systemd 229 and up, so using the old location
to make them work for either version of systemd.

StartLimitBurst=3

Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230.

Both the old, and new name are accepted by systemd 230 and up, so using the old name to make
this option work for either version of systemd.

StartLimitInterval=60s

Having non-zero Limit*s causes performance problems due to accounting overhead
in the kernel. We recommend using cgroups to do container-local accounting.

LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity

Comment TasksMax if your systemd version does not support it.

Only systemd 226 and above support this option.

TasksMax=infinity

set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes

kill only the docker process, not all processes in the cgroup
KillMode=process
OOMScoreAdjust=-500

[Install]
WantedBy=multi-user.target
EOF

启动docker
systemctl daemon-reload
systemctl enable docker # 开机启动docker
systemctl start docker  # 启动docker服务

查看docker是否安装成功
docker info

如果需要在 bash 中添加 docker 自动补全功能,请拷贝yum安装docker服务器目录下的docker文件至 二进制安装同目录下:

安装bash shell 自动补全功能:
yum install -y bash-completion
将该文件拷贝到二进制安装docker 的主机同目录下:
/usr/share/bash-completion/completions/docker

生效:
source /usr/share/bash-completion/completions/docker
source /usr/share/bash-completion/bash_completion

避免不同目录的多次COPY

[root@docker(192.168.1.101) ~/manifests]#ls
default.conf  Dockerfile  html/

[root@docker(192.168.1.101) ~/manifests]#cat Dockerfile
FROM nginx:alpine
COPY ./default.conf /etc/nginx/conf.d
COPY ./html /usr/share/nginx/html

问题:因为需要拷贝不同的文件到不同的目录,所以这里 COPY 不得不使用两次,有什么方法可以优化一下吗?

因为在 linux 上都是以 / 为起点,所以在 Dockerfile 目录中可以建立”绝对路径”。

[root@docker(192.168.1.101) ~/manifests]#mkdir -pv etc/nginx/conf.d
[root@docker(192.168.1.101) ~/manifests]#mv default.conf etc/nginx/conf.d/

[root@docker(192.168.1.101) ~/manifests]#mkdir -pv usr/share/nginx/
[root@docker(192.168.1.101) ~/manifests]#mv html/ usr/share/nginx/

//修改Dockerfile
[root@docker(192.168.1.101) ~/manifests]#vim Dockerfile
FROM nginx:alpine
COPY . /

//创建镜像
[root@docker(192.168.1.101) ~/manifests]#docker build -t hukey:v01 ./

通过模拟建立容器内绝对路径来实现一次拷贝不同文件到不同目录,并生成镜像。

docker容器日志时区问题

启动 ngx 容器命令:

docker run --name ngx -p 80:80 -d nginx:alpine

查看系统日志:

docker 使用中的重点总结【长期更新】

进入容器查看时区:

root@elk(192.168.1.105)/root> docker exec -it ngx sh
/ # date -R
Mon, 27 Jun 2022 10:53:31 +0000    # 格林尼治时间

修改时区启动容器命令:

docker run --name ngx -p 80:80 -v /etc/localtime:/etc/localtime:ro -d nginx:alpine

再次,查日志:

docker 使用中的重点总结【长期更新】

进入容器查看时区:

root@elk(192.168.1.105)/root> docker exec -it ngx sh
/ # date -R
Mon, 27 Jun 2022 19:12:21 +0800     # 东八区时间

在docker-compose 中修改时区建议使用 environment,如下:

version: "3.7"
services:
  nginx:
    container_name: "ngx"
    image: nginx:alpine
    environment:
    - "TZ=Asia/Shanghai"
    labels:
      service: nginx
    logging:
      options:
        labels: "service"
    ports:
    - "80:80"
  httpd:
    container_name: "httpd"
    image: httpd
    environment:
    - "TZ=Asia/Shanghai"
    labels:
      service: httpd
    logging:
      options:
        labels: "service"
    ports:
    - "8080:80"

总结

从上面来看,容器可以通过修改时区来改变业务时间,而然容器在宿主机生成的日志json中, time 始终都是格林尼治时间,如果后期做容器 _elk_时,也需要注意这个时间的转换。

宿主机访问容器内文件

通过容器 rootfs 挂载点来达到访问容器内文件的目的。

root@elk(192.168.1.103)/root> docker inspect ngx | egrep -i mergeddir

or

root@elk(192.168.1.103)/root> docker inspect  -f '{{.GraphDriver.Data.MergedDir}}' ngx

MergedDir : 包含整个容器的文件系统,包括修改。

进入 MergedDir 后,就可以通过本地直接查看到容器内的系统文件。

ls /var/lib/docker/overlay2/8f4fb49a0e948e37daa34454e781ab588ed0e1a8d1584a30833b4de555d17563/merged
bin/  dev/  docker-entrypoint.d/  docker-entrypoint.sh*  etc/  home/  lib/  media/  mnt/  opt/  proc/  root/  run/  sbin/  srv/  sys/  tmp/  usr/  var/

查看镜像构建的 Dockerfile

docker history --format {{.CreatedBy}} --no-trunc=true 镜像id |sed "s/\/bin\/sh\ -c\ \#(nop)\ //g"|sed "s/\/bin\/sh\ -c/RUN/g" | tac

alpine 类型的镜像修改时区

FROM openjdk:8-jdk-alpine
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
    apk add --no-cache tzdata gcc g++ lsof curl bash procps && \
    echo "Asia/Shanghai" > /etc/timezone && \
    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    apk del tzdata

docker 配置网络代理

有些国外镜像,可能需要特殊手段才能获取,配置docker网络代理:

mkdir -pv /etc/systemd/system/docker.service.d

vim /etc/systemd/system/docker.service.d/proxy.conf
[Service]
Environment="HTTP_PROXY=http://192.168.199.108:7890/"
Environment="HTTPS_PROXY=http://192.168.199.108:7890/"
Environment="NO_PROXY=localhost,127.0.0.1,.example.com"

systemctl daemon-reload; systemctl restart docker

docker 映射端口无法访问问题

当 容器映射的端口无法访问时,请检查 net.ipv4.ip_forward 是否开启

sysctl -a | egrep ip_forward
net.ipv4.ip_forward = 1

docker-compose 篇

记录备忘关于docker 的一些要点难点。

docker-compose 中使用 nfs

问题:如果有一台服务器是数据共享服务器,通过nfs提供服务。而通过 docker-compose启动的容器需要去访问共享服务器里的数据,怎么办?

docker-compose v3 提供了直接在 yml 里编写直接访问nfs 服务器的方式。

nfs 服务器配置:

[root@nfs-server(192.168.1.102) ~]#mkdir -pv /www/html
[root@nfs-server(192.168.1.102) ~]#echo 'hello hukey' > /www/html/index.html
[root@nfs-server(192.168.1.102) ~]#cat /etc/exports
/www/html *(rw,no_root_squash)

[root@nfs-server(192.168.1.102) ~]#systemctl start rpcbind ; systemctl start nfs

docker-compose 服务器

[root@node01(192.168.1.101) ~/manifests]#cat docker-compose.yml
version: '3'
services:
  nginx:
    image: nginx:alpine
    ports:
    - '80:80'
    volumes:
      - type: volume
        source: html
        target: /usr/share/nginx/html
        volume:
          nocopy: true

volumes:
  html:
    name: html
    driver_opts:
      type: "nfs"
      o: "addr=192.168.1.102,nolock,soft,rw"
      device: ":/www/html"

执行:

[root@node01(192.168.1.101) ~/manifests]#docker-compose up --build -d

//进入容器查看
[root@node01(192.168.1.101) ~/manifests]#docker exec -it c9d29e39b2ad sh
/ # cd /usr/share/nginx/html/
/usr/share/nginx/html # cat index.html
hello hukey

//查看挂载目录
/usr/share/nginx/html # df | grep www
:/www/html            95497216   1531904  93965312   2% /usr/share/nginx/html

查看 docker 挂载的卷:

[root@node01(192.168.1.101) ~/manifests]#docker volume ls
DRIVER    VOLUME NAME
local     html
[root@node01(192.168.1.101) ~/manifests]#docker inspect html
[
    {
        "CreatedAt": "2022-06-15T13:47:35+08:00",
        "Driver": "local",
        "Labels": {
            "com.docker.compose.project": "manifests",
            "com.docker.compose.version": "2.4.1",
            "com.docker.compose.volume": "html"
        },
        "Mountpoint": "/var/lib/docker/volumes/html/_data",
        "Name": "html",
        "Options": {
            "device": ":/www/html",
            "o": "addr=192.168.1.102,nolock,soft,rw",
            "type": "nfs"
        },
        "Scope": "local"
    }
]

这样就实现了 docker-compose 中直接使用 nfs 挂载卷。

注意:当使用 docker-compose&#xA0;down 删除 容器时, volumes 是不会被清理的。

[root@node01(192.168.1.101) ~/manifests]#docker-compose down
[root@node01(192.168.1.101) ~/manifests]#docker volume ls
DRIVER    VOLUME NAME
local     html

//这里需要手动清理volumes
[root@node01(192.168.1.101) ~/manifests]#docker volume rm html
html
[root@node01(192.168.1.101) ~/manifests]#docker volume ls
DRIVER    VOLUME NAME

docker-compose 使用默认桥接和自建桥接的不同

在有些例子中, docker-compose 使用默认的 bridge 桥接。于是也尝试使用,在使用中发现了一些问题,记录下来。

使用默认 bridge

docker-compose.yml

version: "3.7"
services:
  ngx01:
    container_name: ngx01
    image: nginx:alpine
    ports:
    - 8080:80
    network_mode: bridge
  ngx02:
    container_name: ngx02
    image: nginx:alpine
    ports:
    - 8090:80
    network_mode: bridge

上面的 docker-compose 中创建了 2 个容器,容器名分别为: ngx01ngx02 使用默认的 bridge 桥接

执行 docker-compose up -d

一般来说,在 docker-compose 中的容器在同一个网络,相互可以使用主机名来进行通信。

进入 ngx01 尝试访问 ngx02

[root@kj-test(192.168.1.101) ~/manifests]#docker exec -it ngx01 sh
/ # ping ngx01
^C
/ # ping ngx02
^C

两个主机名都无法进行通信,于是查看 /etc/resolv.conf

/ # cat /etc/resolv.conf
nameserver 223.5.5.5
nameserver 114.114.114.114

当使用docker 默认桥接方式时,在同一网络中的容器是无法通过主机名来进行通信的,而且容器的dns和宿主机的dns一致。

默认 bridge 网络如下:

[root@kj-test(192.168.1.101) ~/manifests]#docker inspect bridge
[
    {
        "Name": "bridge",
        "Id": "e381e982f4da73fd0eaaca0ce2a42c8c2d08f9998392431b82f1476f568058e9",
        "Created": "2022-06-21T15:30:18.685465006+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "60687bf12fe7eb5285112140bde73a6f65eacaa8d0c51e8067d890601a1da989": {
                "Name": "ngx02",
                "EndpointID": "6e0ab23632d296ec5c17624f56293fb2dacaacfe0749326c6359b5ae013690a1",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "af62af2506546bfecb4c71d1e1124d66dec89771cbfa7ef99eb000061f890f5f": {
                "Name": "ngx01",
                "EndpointID": "615895fca193dc912d45c953cc463ed998e6ea2c0d309f73b8e6e85042c62941",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
        },
        "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"
        },
        "Labels": {}
    }
]

使用自建桥接网络

docker-compose.yml

version: "3.7"
services:
  ngx01:
    container_name: ngx01
    image: nginx:alpine
    ports:
    - 8080:80
    networks:
    - xajs_net
  ngx02:
    container_name: ngx02
    image: nginx:alpine
    ports:
    - 8090:80
    networks:
    - xajs_net
networks:
  xajs_net:
    name: xajs_net
    driver: bridge
    ipam:
      config:
      - subnet: "172.100.0.0/16"

上面的 docker-compose 中创建了 2 个容器,1个网络 xajs_net 容器名分别为: ngx01ngx02

执行 docker-compose up -d

进入 ngx01 尝试访问 ngx02

[root@kj-test(192.168.1.101) ~/manifests]#docker exec -it ngx01 sh
/ # ping -w1 -c1 ngx02
PING ngx02 (172.100.0.2): 56 data bytes
64 bytes from 172.100.0.2: seq=0 ttl=64 time=0.716 ms

1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.158/0.158/0.158 ms

两个容器可以通过主机名来通信,查看 /etc/resolv.conf

/ # cat /etc/resolv.conf
nameserver 127.0.0.11
options ndots:0

只有docker自建桥接方式时,在同一网络中的容器是可以主机名来进行通信的。

其中的技术细节,等有时间在深究。

总结

当使用docker 默认桥接方式时,在同一网络中的容器是无法通过主机名来进行通信的,只有docker自建桥接方式时,在同一网络中的容器是可以主机名来进行通信的。

docker-compose 开机自启服务

vim /etc/systemd/system/docker-compose-app.service

[Unit]
Description=Docker Compose Application Service
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/data/containers  # 设置 docker-compose.yaml 所在目录
ExecStart=/usr/bin/docker-compose up -d
ExecStop=/usr/bin/docker-compose down
TimeoutStartSec=0

[Install]
WantedBy=multi-user.target

docker-compose 启动mysql

version: "3.7"
services:
  ruoyi-mysql:
    container_name: mysql
    image: mysql:5.7.18
    environment:
    - "MYSQL_ROOT_PASSWORD=ruoyi@123"
    - "MYSQL_DATABASE=ry-vue"
    - "TZ=Asia/Shanghai"
    restart: always
    volumes:
    - /apps/mysql/mydir:/mydir
    - /apps/mysql/datadir:/var/lib/mysql
    - /apps/mysql/conf/my.cnf:/etc/my.cnf
    - /apps/mysql/source:/docker-entrypoint-initdb.d    # 全备备份sql文件放置到此目录下
    ports:
     - 3306:3306

docker-compose 启动 redis

version: '3'
services:
  redis:
    image: redis
    restart: always
    hostname: redis #指定容器hostname
    container_name: redis
    privileged: true
    ports:
      - 6379:6379
    environment:
      TZ: Asia/Shanghai #timeZone 时区
    volumes:
      # 在当前目录下创建/data /conf /logs
      - ./data:/data
      - ./conf:/etc/redis
      - ./logs:/logs
    command: [ "redis-server", "/etc/redis/redis.conf" ]

redis.conf

cat << 'EOF' > /data/redis/conf/redis.conf
bind 0.0.0.0
protected-mode no
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize no
pidfile /var/run/redis_6379.pid
loglevel notice
logfile ""
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir ./
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync yes
repl-diskless-sync-delay 5
repl-diskless-sync-max-replicas 0
repl-diskless-load disabled
repl-disable-tcp-nodelay no
replica-priority 100
acllog-max-len 128
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes
appendonly no
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
aof-timestamp-enabled no

slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-listpack-entries 512
hash-max-listpack-value 64
list-max-listpack-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-listpack-entries 128
zset-max-listpack-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
EOF

docker-compose 顺序问题处理

比如 tomcat 比 mysql 启动要快,每次 tomcat都会先报错,怎么解决?

最简单直接的方式就是为 tomcat 容器启用
restart: always
第二contacts 重启就能连接dm8了。

Original: https://www.cnblogs.com/hukey/p/16378311.html
Author: hukey
Title: docker 使用中的重点总结【长期更新】

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/534599/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球