运维(37) Docker入门到实战

文章目录

一、Docker是什么?

Docker 是一个开源的应用容器引擎,让开发者可以打包应用以及依赖包到一个可移植的镜像中,然后发布到Linux或Windows操作系统的机器上。

ex:
前端Vue需要build打包在nginx环境部署;
后端Java需要java -jar app.jar运行;
前后端需要安装不同的环境去部署运行。
这个时候我们可以通过docker容器统一的环境去一键运行发布这些应用docker run ...

Docker 包括三个基本概念:

  1. 镜像(Image):一个特殊文件系统。ex: ubuntu系统。
  2. 容器(Container):容器是镜像运行时的实体。容器可以被创建、启动、停止、删除等。
  3. 仓库(Repository):保存镜像。 ex: https://hub.docker.com
    • public(共有仓库):免费上传、下载公开的镜像。
    • private(私有仓库):需要认证才能上传、下载镜像。

在这里插入图片描述

二、Docker安装与卸载

可参考 https://docs.docker.com/engine/install/centos
tips: 这里安装基于 CentOS Linux release 7.6.1810 (Core)

1、安装
# 配置yum源
sudo yum install -y yum-utils
sudo yum-config-manager \
    --add-repo \
    http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo


# 通过yum源安装docker
# sudo yum -y install docker
# 指定版本安装
sudo yum install -y docker-ce-20.10.7 docker-ce-cli-20.10.7 containerd.io-1.4.6

# 启动docker
sudo systemctl start docker
# 重启docker 
sudo systemctl restart docker
# 开机自启
sudo systemctl enable docker
# 设置开机自启 & 现在启动
sudo systemctl enable --now docker

# 查看运行情况
sudo systemctl status docker

# 测试
docker run --rm alpine ping -c 5 baidu.com
2、配置镜像加速器
# 修改daemon配置文件`/etc/docker/daemon.json`
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["加速器地址"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
# 查看 `Registry Mirrors`
docker info
3、卸载
# 查看yum安装的docker软件包
yum list installed |grep docker
# 删除相关软件包
yum -y remove docker* containerd.io
# 删除关联数据
rm -rf /var/lib/docker
rm -rf /var/lib/containerd

三、Docker运行Nginx

# 拉取镜像
docker pull nginx

# 运行
# –name 定义一个容器的名字,如果在执行docker run时没有指定Name,那么deamon会自动生成一个随机数字符串当做UUID。
# -d 标识是让 docker 容器在后台运行。
# -p 标识通知 Docker 将容器内部使用的网络端口映射到我们使用的主机上。
docker run --name nginx -d -p 8080:80 nginx

访问 http://127.0.0.1:8080
在这里插入图片描述

四、Docker运行Java项目

# docker拉取java jdk环境
docker pull java:latest

# 运行项目
# 1、原生jar运行方式
java -jar xx.jar --spring.profiles.active=prod

# 2、java镜像环境运行方式
docker run -d -p 3001:3001 --restart=always -v /zhengqingya/code/demo/app.jar:/tmp/app.jar --name springboot java:latest java -jar /tmp/app.jar

# 3、可远程调试运行方式
docker run -d -p 5000:5000 -p 50001:50001 --name demo \
-v /zhengqingya/code/demo/app.jar:/tmp/app.jar \
java:latest \
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=50001 -jar /tmp/app.jar --spring.profiles.active=prod

# 4、从镜像仓库拉取运行方式
docker run -d -p 5000:5000 -p 50001:50001 \
-e PROFILE=prod \
--restart always \
--name demo \
registry.cn-hangzhou.aliyuncs.com/zhengqing/demo


# arthas 相关
docker exec -it demo /bin/sh -c "wget https://alibaba.github.io/arthas/arthas-boot.jar && java -jar arthas-boot.jar"

docker exec -it demo /bin/sh -c "java -jar /opt/arthas/arthas-boot.jar"

五、Docker常用命令

# 查看当前docker版本
docker -v

# 列出容器 -- 仅运行的容器
docker ps 
# 列出容器 -- 包含停止的容器
docker ps -a

# 查看当前本地所有镜像
docker images

# 启动容器
docker start 容器id
# 重启容器
docker restart 容器id
# 杀掉一个运行中的容器
docker kill -s KILL 容器id
# 停止容器 
docker stop 容器id
# 删除容器
docker rm 容器id
# 删除一个或多少容器。-f :通过SIGKILL信号强制删除一个运行中的容器-l :移除容器间的网络连接,而非容器本身-v :-v 删除与容器关联的卷
docker rm -f xx、xx2

# 删除镜像 【 顺序:停止镜像里的容器,再删除容器,最后再删除镜像 】
docker rmi 镜像id

# 列出所有的容器 ID
docker ps -aq
# 停止所有的容器
docker stop $(docker ps -aq)
# 删除所有的容器
docker rm $(docker ps -aq)
# 删除所有的镜像
docker rmi $(docker images -q)

# 停止并删除容器
docker ps -a | grep 容器ID | awk '{print $1}' | xargs -i docker stop {} | xargs -i docker rm {}

# 删除镜像
# docker images 获取所有images
# grep -E "xxxxx" 筛选到特定的images
# awk ‘ {print $3}’ 打印第三列 即image id列
# uniq 检查及删除文本文件中重复出现的行列
# xargs -I {} 多行转单行
# docker rmi --force {} 删除所有指定id
docker images | grep -E "xxx" | awk '{print $3}' | uniq | xargs -I {} docker rmi --force {}
# ex: 删除镜像 `redis:latest`
docker images | grep -E redis | grep latest| awk '{print $3}' | uniq | xargs -I {} docker rmi --force {}

# 删除所有停止的容器
docker container prune

# 删除所有不使用的镜像
docker image prune --force --all
# 或
docker image prune -f -a

# 查看容器运行内存信息  【参数`mem_limit: 300m` # 最大使用内存】
docker stats nacos_server
# CONTAINER           CPU %               MEM USAGE / LIMIT   MEM %               NET I/O             BLOCK I/O           PIDS
# nacos_server        19.18%              264 MiB / 300 MiB   87.99%              172 kB / 99.9 kB    39.4 MB / 127 kB    145

# 进入容器
docker exec -it 容器ID /bin/bash
# 以交互模式启动一个容器,在容器内执行/bin/bash命令
docker run -i -t 容器ID /bin/bash

# 查看容器日志 -t:显示时间戳
docker logs -f -t 容器id
docker logs -fn10 -t 容器id

# 登陆镜像仓库
docker login
# 登录阿里云仓库
docker login -u 用户名 -p 密码 registry.cn-hangzhou.aliyuncs.com

# 获取镜像
docker pull 镜像仓库地址
# 上传镜像
docker push 镜像仓库地址

# 查看镜像的创建历史
docker history 镜像仓库地址

# 构造镜像
# 用法 docker build -t 镜像名称 .
docker build -t docker_demo .

# 查询mysql容器端口
docker inspect mysql | grep IPAddress

六、Docker认证私有仓库

认证
docker login --username=用户名 仓库地址
# ex:认证阿里云
docker login --username=xxx registry.cn-hangzhou.aliyuncs.com
查看密码

config.json 会记录登录之后的用户名和密码,只是base64加密之后的密码。

# 查看密码
cat ~/.docker/config.json

# ex:
{
        "auths": {
                "ccr.ccs.tencentyun.com": {
                        "auth": "TMAxxx1Ng=="
                },
                "registry.cn-hangzhou.aliyuncs.com": {
                        "auth": "emhxxxnLg=="
                }
        }
}

# 解密
echo 'emhxxxnLg==' | base64 --decode
# username:password
移除认证凭证
docker logout 仓库地址
# 移除阿里云认证
docker logout registry.cn-hangzhou.aliyuncs.com

七、Docker基于容器创建一个新的镜像

# -a :提交的镜像作者;
# -c :使用Dockerfile指令来创建镜像;
# -m :提交时的说明文字;
# -p :在commit时,将容器暂停。

# 基于容器创建一个新的镜像
docker commit -m "This is MySQL Database 5.7 image" -a "zhengqingya" mysql_server_test registry.cn-hangzhou.aliyuncs.com/zhengqing/mysql5.7:latest
# push
docker push registry.cn-hangzhou.aliyuncs.com/zhengqing/mysql5.7:latest

ex: 提交一个centos6.6
# 拉取镜像
docker pull centos:6.6
docker images
# 运行进入
docker run -i -t centos:6.6 bash
ls
mkdir -p /zhengqingya/soft
cd zhengqingya
echo '测试' > test.txt
exit
# 查看操作
docker ps -a
docker diff centos镜像id
# 提交镜像
docker commit -m "测试提交" -a "zhengqingya" centos镜像id registry.cn-hangzhou.aliyuncs.com/zhengqing/centos:latest
docker push registry.cn-hangzhou.aliyuncs.com/zhengqing/centos:latest
# pull自己制作的镜像
docker pull registry.cn-hangzhou.aliyuncs.com/zhengqing/centos:latest
docker run -i -t registry.cn-hangzhou.aliyuncs.com/zhengqing/centos:latest bash
ex: 提交redis
# 运行进入
docker run --name redis_server -p 6379:6379 -d redis:latest redis-server
ls
mkdir -p /zhengqingya/soft
cd zhengqingya
echo '测试' > test.txt
exit
# 查看操作
docker ps -a
docker diff centos镜像id
# 提交镜像
docker commit -m "测试提交" -a "zhengqingya" centos镜像id registry.cn-hangzhou.aliyuncs.com/zhengqing/redis_test:latest
docker push registry.cn-hangzhou.aliyuncs.com/zhengqing/redis_test:latest
# pull自己制作的镜像
docker run --name redis_test_server -p 6000:6379 -d registry.cn-hangzhou.aliyuncs.com/zhengqing/redis_test:latest redis-server
ex: 提交jenkins
# 检查容器里文件结构的更改
docker diff jenkins
# 提交镜像
docker commit -m "测试提交jenkins" -a "zhengqingya" jenkins registry.cn-hangzhou.aliyuncs.com/zhengqing/jenkins:v1
docker push registry.cn-hangzhou.aliyuncs.com/zhengqing/jenkins:v1
# 运行测试
docker run -d --name jenkins_test -p 10000:8080 -u root registry.cn-hangzhou.aliyuncs.com/zhengqing/jenkins:v1

八、Docker保存镜像

1、准备一个修改过后的镜像
# 拉取nginx镜像
docker pull nginx

# 运行
docker run --name nginx -d -p 8080:80 nginx

# 进入容器
docker exec -it nginx /bin/bash

# 修改
echo '<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>nginx容器运行中...</title>
</head>
<body>
    <h1> Hello World </h1>
    <p> If I were you. </p>
</body>
</html>' > /usr/share/nginx/html/index.html

# 基于容器创建一个新的镜像
# -a :提交的镜像作者;
# -c :使用Dockerfile指令来创建镜像;
# -m :提交时的说明文字;
# -p :在commit时,将容器暂停。
docker commit -m "This is my nginx image" -a "zhengqingya" nginx my-nginx:v1
2、导出镜像
docker save -o my-nginx.tar my-nginx:v1
3、导入镜像
# 先删除已存在的旧容器
docker rm -f nginx
# 删除旧镜像
docker rmi my-nginx:v1
docker rmi nginx


# 导入使用 `docker save` 命令导出的镜像
docker load -i my-nginx.tar
# 查看镜像
docker images
# 运行
docker run --name nginx -d -p 8080:80 my-nginx:v1

九、Docker镜像推送

# 获取镜像
docker pull 镜像仓库地址

# 登录阿里云仓库
docker login -u 用户名 -p 密码 registry.cn-hangzhou.aliyuncs.com

# 将本地镜像名 改为 一个新镜像仓库地址
docker tag 镜像名 新镜像仓库地址
# 推送镜像
docker push 新镜像仓库地址


# 举例
docker pull nginx
docker tag nginx registry.cn-hangzhou.aliyuncs.com/zhengqing/nginx:latest
docker push registry.cn-hangzhou.aliyuncs.com/zhengqing/nginx:latest

十、Docker配置远程连接2375端口

Docker常见端口

2375:未加密的docker socket,远程root无密码访问主机
2376:tls加密套接字,很可能这是您的CI服务器4243端口作为https 443端口的修改
2377:群集模式套接字,适用于群集管理器,不适用于docker客户端
5000:docker注册服务
4789和7946:覆盖网络
1、修改宿主机配置文件
法一
vim /lib/systemd/system/docker.service

ExecStart 开头的这一行末尾添加 -H tcp://0.0.0.0:2375

ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock

在这里插入图片描述

法二
vim /etc/docker/daemon.json


{
  "hosts": ["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"]
}
法三
vim /etc/default/docker

# 加入下面一行
DOCKER_OPTS="-H tcp://0.0.0.0:2375"
2、重启docker
systemctl daemon-reload && systemctl restart docker
3、防火墙开放2375端口
firewall-cmd --zone=public --add-port=2375/tcp --permanent
4、通过外网访问测试成功

http://ip地址:2375/version
在这里插入图片描述

# 查看docker版本
docker -H tcp://www.zhengqingya.com:2375 version
# 查看镜像包
docker -H tcp://www.zhengqingya.com:2375 images

十一、Docker容器和宿主机文件互传

# 从容器`mysql_master`里面拷文件到宿主机  前:容器文件路径  后:宿主机路径
docker cp mysql_master:/tmp/all.sql /tmp/all.sql

# 从宿主机拷文件到容器`mysql_slave`里面  前:宿主机文件路径 后:容器路径
docker cp /tmp/all.sql mysql_slave:/tmp/all.sql

十二、Docker容器中执行宿主机docker命令

将docker宿主机的docker文件和docker.sock文件挂载到容器中即可

-v /var/run/docker.sock:/var/run/docker.sock 
-v /usr/bin/docker:/usr/bin/docker
-v /usr/lib64/libltdl.so.7:/usr/lib/x86_64-linux-gnu/libltdl.so.7

# 把docker相关的命令和依赖使用-v挂载到容器
docker run -it -d  \
--restart=always -u root \
-v /usr/bin/docker:/usr/bin/docker \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/lib64/libltdl.so.7:/usr/lib/x86_64-linux-gnu/libltdl.so.7 镜像名称

-u root          
#以root的身份去运行镜像(避免在容器中调用Docker命令没有权限)
#最好使用docker用户去运行

-v /usr/bin/docker:/usr/bin/docker
#将宿主机的docker命令挂载到容器中
#可以使用which docker命令查看具体位置
#或者把挂载的参数改为: -v $(which docker):/usr/bin/docker

-v /var/run/docker.sock:/var/run/docker.sock
#容器中的进程可以通过它与Docker守护进程进行通信

-v /usr/lib64/libltdl.so.7:/usr/lib/x86_64-linux-gnu/libltdl.so.7
#libltdl.so.7是Docker命令执行所依赖的函数库
#容器中library的默认目录是 /usr/lib/x86_64-linux-gnu/
#把宿主机的libltdl.so.7 函数库挂载到该目录即可
#可以通过whereis libltdl.so.7命令查看具体位置
#centos7位置/usr/lib64/libltdl.so.7
#ubuntu位置/usr/lib/x86_64-linux-gnu/libltdl.so.7

举例

docker run -d -p 3307:3306 --name docker_test \
-v /usr/bin/docker:/usr/bin/docker \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/lib64/libltdl.so.7:/usr/lib/x86_64-linux-gnu/libltdl.so.7 \
-e MYSQL_ROOT_PASSWORD=root \
registry.cn-hangzhou.aliyuncs.com/zhengqing/mysql:5.7

十三、Docker镜像与容器自动更新之Watchtower

1、自动清除旧镜像

每次更新都会把旧的镜像清理掉, --cleanup 选项可以简写为 -c

docker run -d \
    --name watchtower \
    --restart unless-stopped \
    -v /var/run/docker.sock:/var/run/docker.sock \
    containrrr/watchtower \
    --cleanup
2、选择性自动更新

ex: 只自动更新nginxredis 容器

docker run -d \
    --name watchtower \
    --restart unless-stopped \
    -v /var/run/docker.sock:/var/run/docker.sock \
    containrrr/watchtower -c \
    nginx redis

可以建立一个更新列表文件, 然后通过变量的方式去调用这个列表

cd /zhengqingya/soft/docker
# ① 
echo 'small-tools
      code-api' > watchtower.list

# ② 
docker run -d \
    --name watchtower \
    --restart unless-stopped \
    -v /var/run/docker.sock:/var/run/docker.sock \
    containrrr/watchtower -c \
    $(cat ~/.watchtower.list)
3、设置自动更新检查频率

默认情况下 Watchtower 每 5 分钟会轮询一次,如果你觉得这个频率太高了可以使用如下选项来控制更新检查的频率,但二者只能选择其一
–interval, -i - 设置更新检测时间间隔,单位为秒。比如每隔 1 个小时检查一次更新

docker run -d \
    --name watchtower \
    --restart unless-stopped \
    -v /var/run/docker.sock:/var/run/docker.sock \
    containrrr/watchtower -c \
    --interval 3600

–schedule, -s - 设置定时检测更新时间。格式为 6 字段 Cron 表达式,而非传统的 5 个字段。比如每天凌晨 2 点检查一次更新

docker run -d \
    --name watchtower \
    --restart unless-stopped \
    -v /var/run/docker.sock:/var/run/docker.sock \
    containrrr/watchtower -c \
    --schedule "0 2 * * * *"
4、最终实战命令
docker run -d \
    --name watchtower \
    --restart unless-stopped \
    -v /var/run/docker.sock:/var/run/docker.sock \
    containrrr/watchtower -c \
    $(cat $PWD/watchtower.list) \
    -i 30

十四、解决Docker容器内无法访问外网问题

tips: 由于环境不同,问题的解决方法也自然不同,下面是小编所在环境的解决方式 ^_^

法一:重建网络docker0
sudo service docker stop
sudo pkill docker
sudo iptables -t nat -F
sudo ifconfig docker0 down
sudo brctl delbr docker0
sudo service docker start
法二:开启宿主机的ipv4转发功能
# 修改配置
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf

# 重启network
systemctl restart network

# 查看 (0->标识未开启 1->标识开启)
sysctl net.ipv4.ip_forward
# net.ipv4.ip_forward = 1

# 重启docker
systemctl restart docker
法三:使用--net=host宿主机网络方式启动容器
# 示例
docker run --net=host --name ubuntu_bash -i -t ubuntu:latest /bin/bash

docker run --net=host --rm alpine ping -c 5 baidu.com
法四:关闭SELinux
# 查看SELinux状态
getenforce

# 临时关闭SELinux
setenforce 0

# 永久关闭SELinux
vim /etc/selinux/config
# 将 `SELINUX=enforcing` 改成 `SELINUX=disabled`

# 重启liunx
reboot
法五

参考 https://github.com/coolsnowwolf/lede/issues/1760

# 修改配置
echo "net.bridge.bridge-nf-call-ip6tables = 1" >> /etc/sysctl.conf
echo "net.bridge.bridge-nf-call-iptables = 1" >> /etc/sysctl.conf
echo "net.bridge.bridge-nf-call-arptables = 1" >> /etc/sysctl.conf

# Luci > 网络 > 防火墙 > 转发:接受
# Luci > 状态 > 防火墙 > 重启防火墙

service docker restart
法六
rm -rf /var/lib/docker/network/*

systemctl restart docker
法七:修改DNS客户端解析文件resolv.conf
# 写入Liunx的DNS客户端解析文件resolv.conf里
#                 114.114.114.114 => 国内移动、电信和联通通用的DNS
#                 8.8.8.8 => google提供,更适合国外以及访问国外网站的用户使用
# echo nameserver 8.8.8.8 > /etc/resolv.conf
echo nameserver 114.114.114.114 > /etc/resolv.conf

# 查看配置
cat /etc/resolv.conf

# 测试
docker run --rm alpine ping -c 5 baidu.com
法八:和网络工程师沟通下是否做了一定限制
# 先运行一个访问外网的程序
docker run --rm alpine ping -c 50 baidu.com

# 安装tcpdump
yum install tcpdump
# 利用tcpdump进行抓包分析
tcpdump -i docker0 icmp
# 发现有request包,表明本机到baidu的包,baidu是接收到的,可能是百度没响应(可能性不大)或者被公司防火墙阻断了

在这里插入图片描述

法九:宿主机防火墙开启伪装IP功能

tips: 感觉无用,小编直接关防火墙也没解决网络问题

# 查看防火墙状态
firewall-cmd --state
# 查看防火墙是否开启ip地址转发(ip地址伪装)
firewall-cmd --query-masquerade
# 开启ip地址转发
firewall-cmd --add-masquerade --permanent
# 将网络接口 docker0 加入 trusted zone,解决 DNS 问题
firewall-cmd --permanent --zone=trusted --add-interface=docker0
# 更新防火墙规则
firewall-cmd --reload
法十:重装docker

此方式乃是最后无奈之举了…


临时测试容器内能够ping
docker run --rm alpine ping -c 5 baidu.com
小编个人问题记录 – 未解决

基于电信网环境,在局域网window上安装centos7.6系统,宿主机能正常访问外网,但容器内不行,且容器内dns解析有问题;
如果直接访问ip的话,tcpdump抓包docker0发现只有请求,无任何响应。

临时使用--net=host方式解决外网访问问题,还待持续研究!

十五、Dockerfile构建应用镜像

ex: 构建一个java的jar运行

1、Dockerfile
# 拉取jdk基础镜像
FROM openjdk:8-jdk-alpine

# 维护者信息
MAINTAINER zhengqingya

# 添加jar包到容器中 -- tips: xx.jar 和 Dockerfile 在同一级
ADD app.jar /home/

# 对外暴漏的端口号
# [注:EXPOSE指令只是声明容器运行时提供的服务端口,给读者看有哪些端口,在运行时只会开启程序自身的端口!!]
EXPOSE 80

# 运行🏃🏃🏃
CMD java -jar /home/app.jar
2、构建镜像
# 构建镜像 -f:指定Dockerfile文件路径 --no-cache:构建镜像时不使用缓存
docker build -f Dockerfile -t "registry.cn-hangzhou.aliyuncs.com/zhengqingya/demo:dev" . --no-cache
3、运行
# 运行
docker run -d -p 80:80 --name app registry.cn-hangzhou.aliyuncs.com/zhengqingya/demo:dev
# 进入容器
docker exec -it app /bin/sh
cd /home

十六、Docker可视化管理工具 – Portainer

docker run -d -p 9000:9000 --restart=always --name portainer -v /var/run/docker.sock:/var/run/docker.sock registry.cn-hangzhou.aliyuncs.com/zhengqing/portainer:1.24.1

在这里插入图片描述

十七、docker-compose

请移步 https://gitee.com/zhengqingya/docker-compose.git
通过docker-compose编排一系列环境进行一键快速部署运行,小白运维神器。

使用举例 – 部署MySQL5.7

# 环境准备
git clone https://gitee.com/zhengqingya/docker-compose.git
cd docker-compose/Liunx
# 运行
docker-compose -f docker-compose-mysql5.7.yml -p mysql5.7 up -d

今日分享语句:
不要失去信心,只要坚持不懈,就终会有成果的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郑清

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值