Docker 持续集成部署+ELK日志相关等 完美实践

docker(ubuntu)

卸载docker

# 卸载(如有)
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done

安装docker

# 更新并安装工具
sudo apt-get update
sudo apt-get install ca-certificates curl

# 添加阿里云GPG秘钥
sudo curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# 配置docker软件源信息到阿里云
sudo echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 安装docker
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 启动并测试
sudo systemctl start docker
sudo docker run hello-world

# 校验(出现这个,说明安装成功了)
Hello from Docker!
This message shows that your installation appears to be working correctly.
...

更改docker国内镜像

# 阿里云镜像加速用不了,使用下面这个试试
echo '{"registry-mirrors": ["https://docker.1ms.run"]}' | sudo tee /etc/docker/daemon.json > /dev/null
systemctl daemon-reload
systemctl restart docker

更改docker存储位置

# 更改docker存储位置,假如想存在/data/docker目录里
cd /data
mkdir docker
# 修改 /etc/docker/daemon.json,在根对象增加 "data-root": "/data/docker" 配置

安装docker-compose

# 下载docker-compose
# 版本需要替换到最新,从下面链接查看
# https://github.com/docker/compose/releases
curl -L "https://github.com/docker/compose/releases/download/v2.32.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 增加执行权限
chmod +x /usr/local/bin/docker-compose

jenkins

拉取镜像

docker pull jenkins/jenkins 

创建挂载目录

mkdir -p /data/jenkins/{jenkins_home,docker.sock}

创建启动Jenkins容器

docker run -d \
  --name jenkins \
  --user $(id -u):$(id -g) \
  -p 9080:8080 \
  -p 50000:50000 \
  -v /data/jenkins/jenkins_home:/var/jenkins_home \
  -v /data/jenkins/docker.sock:/var/run/docker.sock \
  -v $(which docker):/usr/bin/docker \
  --restart=always \
  jenkins/jenkins

详细解释:

# 使用 Docker 运行一个新的容器
docker run -d \
  # 为容器指定一个名字
  --name jenkins \
  # 以当前用户身份运行容器内的进程,$(id -u) 获取当前用户的用户ID,$(id -g) 获取当前用户的组ID
  --user $(id -u):$(id -g) \
  # 将宿主机的端口 9010 映射到容器的端口 8080,用于访问 Jenkins 的 Web 界面
  -p 9080:8080 \
  # 将宿主机的端口 9011 映射到容器的端口 50000,用于 Jenkins 的 JNLP 代理连接
  -p 50000:50000 \
  # 将宿主机上的 /data/jenkins/jenkins_home 目录挂载到容器的 /var/jenkins_home 目录,用于持久化 Jenkins 数据
  -v /data/jenkins/jenkins_home:/var/jenkins_home \
  # 将宿主机上的 Docker 套接字文件挂载到容器中,使得容器内的 Jenkins 可以使用宿主机的 Docker 守护进程
  -v /data/jenkins/docker.sock:/var/run/docker.sock \
  # 将宿主机上的 Docker 命令挂载到容器中,使得容器内的 Jenkins 可以执行 Docker 命令
  -v $(which docker):/usr/bin/docker \
  # 指定要运行的镜像,这里是 Jenkins 官方提供的 Jenkins 镜像
  jenkins/jenkins

查看jenkins 解锁密码

docker logs  -f jenkins

 如下所示
*************************************************************
*************************************************************
*************************************************************

Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:

6f1c8e1131974079ace00e89507c6a16

This may also be found at: /var/jenkins_home/secrets/initialAdminPassword

*************************************************************
*************************************************************
*************************************************************

设置密码

admin admin123

Jenkins dotnet命令无法执行

docker exec -it jenkins bash

#dotnet
apt-get install wget

wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb

dpkg -i packages-microsoft-prod.deb

apt-get update

apt-get install dotnet-sdk-6.0

添加自定义Nuget源

docker exec -it jenkins bash

cd ~/.nuget/NuGet
# 添加第一个源# 
sed -i '/<\/packageSources>/i \    <add key="ZbirdNuGet" value="http://nuget.zbird.co/nuget" />' NuGet.Config

# 添加第二个源
sed -i '/<\/packageSources>/i \    <add key="ZbirdSandboxNuGet" value="http://nuget.sandbox.zbird.co/nuget" />' NuGet.Config

将现有容器打包成镜像

# docker commit -m "提交信息" -a "作者" <容器ID或名称> mynewimage:latest
docker commit -m '配置后的jenkins' -a 'TE' jenkins myjenkins:1.0

配置NodeJs

系统管理 => 插件管理 => 安装NodeJS
系统管理 => 全局工具配置 => NodeJS安装 => 勾选自动安装 选择需要的 NodeJS 版本
配置流水线 => 环境 => 为PATH提供Node 和 npm bin/文件夹 (Provide Node & npm bin/ folder to PATH)=> 选择你在全局工具配置的nodejs 名  即可

apollo

部署mysql

# 拉取mysql镜像
docker pull mysql:5.7.44

# 创建mysql挂载目录
mkdir -p /data/mysql/{log,data,conf.d}
# 创建mysql配置文件
echo "" > /data/mysql/my.cnf

# 启动mysql容器
docker run -d --restart=always --name mysql \
-v /data/mysql/data:/var/lib/mysql \
-v /data/mysql/log:/var/log/mysql \
-v /data/mysql/conf.d:/etc/mysql/conf.d \
-v /data/mysql/my.cnf:/etc/my.cnf \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=NCwkaR14 \
mysql:5.7.44

初始化数据库

  1. 使用docker-compose 部署本地apollo - 高宏顺 - 博客园
  2. 最终创建多环境数据库,ApolloConfigDB每个环境一个

拉取apollo镜像

docker pull apolloconfig/apollo-portal
docker pull apolloconfig/apollo-configservice
docker pull apolloconfig/apollo-adminservice

创建docker-compose.yaml

# 创建目录
mkdir -p /etc/apollo

# 创建docker-compose文件,复制下面的ymal进去保存
vim /etc/apollo/docker-compose.yaml

version: '4'
services:
  # DEV
  apollo-configservice-dev:
    image: apolloconfig/apollo-configservice    
    environment:
      # jdbc mysql 地址
      SPRING_DATASOURCE_URL: jdbc:mysql://192.168.0.16:3306/ApolloConfigDB_DEV?useSSL=false&characterEncoding=utf8
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: NCwkaR14 # 密码需要替换
      SERVER_PORT: 8080
    network_mode: host

  apollo-adminservice-dev:
    image: apolloconfig/apollo-adminservice    
    depends_on:
      - apollo-configservice-dev
    environment:
      # jdbc mysql 地址
      SPRING_DATASOURCE_URL: jdbc:mysql://192.168.0.16:3306/ApolloConfigDB_DEV?useSSL=false&characterEncoding=utf8
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: NCwkaR14 # 密码需要替换
      SERVER_PORT: 8090
    network_mode: host

  apollo-configservice-pro:
    image: apolloconfig/apollo-configservice    
    environment:
      # jdbc mysql 地址
      SPRING_DATASOURCE_URL: jdbc:mysql://192.168.0.16:3306/ApolloConfigDB_PRO?useSSL=false&characterEncoding=utf8
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: NCwkaR14 # 密码需要替换
      SERVER_PORT: 8081
    network_mode: host

  apollo-adminservice-pro:
    image: apolloconfig/apollo-adminservice    
    depends_on:
      - apollo-configservice-pro
    environment:
      # jdbc mysql 地址
      SPRING_DATASOURCE_URL: jdbc:mysql://192.168.0.16:3306/ApolloConfigDB_PRO?useSSL=false&characterEncoding=utf8
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: NCwkaR14 # 密码需要替换
      SERVER_PORT: 8091
    network_mode: host

  apollo-portal:
    image: apolloconfig/apollo-portal
    depends_on:
      - apollo-adminservice-dev
      - apollo-adminservice-pro
    environment:
      # jdbc mysql 地址
      SPRING_DATASOURCE_URL: jdbc:mysql://192.168.0.16:3306/ApolloPortalDB?useSSL=false&characterEncoding=utf8
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: NCwkaR14 # 密码需要替换      
      SERVER_PORT: 8070
    network_mode: host

执行docker 命令

# 安装yaml 
docker-compose -f /etc/apollo/docker-compose.yaml up -d
# 默认账号密码:用户名:apollo 密码:admin

# 卸载yaml 
docker-compose -f /etc/apollo/docker-compose.yaml down

# 重启yaml 
docker-compose -f /etc/apollo/docker-compose.yaml restart

docker私有仓

拉取镜像

# 拉取registry镜像
docker pull registry

修改docker的daemon文件

"insecure-registries": ["192.168.0.16:5000"]
  1. 增加"insecure-registries"节点:
    1. 直接IP+端口即可

重启docker

# 重新加载文件
systemctl daemon-reload
# 重启docker
systemctl restart docker

registry配置文件

有两种方式,选择其中之一即可,无论哪种方式,先创建目录

# 创建配置文件存放目录
mkdir -p /data/docker/registry

方式一:从容器内部复制

# 启动一个容器
docker run -d -p 5000:5000 --name registry2 -v /data/etc/registry:/var/lib/ registry registry
# 复制容器内配置文件
docker cp registry2:/etc/docker/registry/config.yml /data/docker/registry/config.yml
# 删除容器
docker rm registry2
# 修改配置文件,增加Access-Control-Allow-Origin和Access-Control-Allow-Methods节点
http:
  addr: :5000
  headers:
    X-Content-Type-Options: [nosniff]
    # 增加这一行
    Access-Control-Allow-Origin: ['*']
    # 增加这一行
    Access-Control-Allow-Methods: ['*']

方式二:使用现有文件

  1. 文件名,命名为:config.yml

  2. 复制以下内容到配置文件中

    命名为 config.yml

    version: 0.1
    log:
    fields:
    service: registry
    storage:
    cache:
    blobdescriptor: inmemory
    filesystem:
    rootdirectory: /var/lib/registry
    http:
    addr: :5000
    headers:
    X-Content-Type-Options: [nosniff]
    Access-Control-Allow-Origin: ['']
    Access-Control-Allow-Methods: ['
    ']
    health:
    storagedriver:
    enabled: true
    interval: 10s
    threshold: 3

启动镜像仓容器

# 启动容器
docker run -d -p 5000:5000 --name registry \
-v /data/docker/registry:/var/lib/registry \
-v /data/docker/registry/config.yml:/etc/docker/registry/config.yml \
--restart=always \
registry

测试容器是否启动成功

# 测试是否部署成功
curl -XGET http://192.168.0.16:5000/v2/_catalog

# 若成功会返回:
# {"repositories":[]}

测试推送、拉取镜像

# 测试推送镜像
docker pull nginx

# 打标签
docker tag nginx:latest 192.168.0.16:5000/nginx

# 上传
docker push 192.168.0.16:5000/nginx

# 校验镜像是否上传成功
curl -XGET http://192.168.0.16:5000/v2/_catalog
# 若推送成功,会返回:
# {"repositories":["nginx"]}

# 拉取镜像
# 删除现有镜像
docker rmi 192.168.0.16:5000/nginx:latest

# 拉取镜像
docker pull 192.168.0.16:5000/nginx

es+kibana

version: '3'
services:
  elasticsearch:
    image: elasticsearch:8.16.2
    restart: unless-stopped
    container_name: elasticsearch
    environment:
      - "discovery.type=single-node"
      - "cluster.name=docker-cluster"
      - "network.host=0.0.0.0"
      - "http.cors.enabled=true"
      - "http.cors.allow-headers=Authorization,X-Requested-With,Content-Length,Content-Type"
      - "xpack.security.enabled=false"
      - "ELASTIC_PASSWORD=123456"
      - "ES_JAVA_OPTS=-Xms2g -Xmx2g"
    volumes:
      - /data/elasticsearch/data:/usr/share/elasticsearch/data
      - /data/elasticsearch/logs:/usr/share/elasticsearch/logs
      - /data/elasticsearch/plugins:/usr/share/elasticsearch/plugins
        #- /data/elasticsearch/config:/usr/share/elasticsearch/config # 容器内没权限获取这个文件夹权限
    ports:
      - "9200:9200"
      - "9300:9300"
    networks:
      - elastic_net

  kibana:
    image: kibana:8.16.2
    container_name: kibana
    restart: unless-stopped
    depends_on:
      - elasticsearch
    environment:
      - "ELASTICSEARCH_HOSTS=http://elasticsearch:9200"
      - "ELASTICSEARCH_USERNAME=elastic"
      - "ELASTICSEARCH_PASSWORD=123456"
      - "monitoring.ui.container.elasticsearch.enabled:true"
    ports:
      - "5601:5601"
    networks:
      - elastic_net

networks:
  elastic_net:
    driver: bridge

由于容器权限问题 需要先将部分文件

  #- /data/elasticsearch/config:/usr/share/elasticsearch/config # 容器内没权限获取这个文件夹权限
  1. 先注释这行 将容器跑起来
  2. 拷贝配置文件到本地
  3. 创建用户
  4. 卸载容器
  5. 重新安装

拷贝文件

docker cp elasticsearch:/usr/share/elasticsearch/data /opt/elasticsearch/
docker cp elasticsearch:/usr/share/elasticsearch/plugins /opt/elasticsearch/
docker cp elasticsearch:/usr/share/elasticsearch/config /opt/elasticsearch/

创建用户

创建新账户
elasticsearch-users useradd kibana

给账户授权
elasticsearch-users roles -a superuser username
elasticsearch-users roles -a kibana_system username

nuget

redis

拉取镜像

docker pull redis

创建映射目录

mkdir -p /data/redis/{conf,data,log}

启动redis

docker run -d \
  --name redis \
  -p 6379:6379 \
  -v /data/redis/conf/redis.conf:/etc/redis/redis.conf \
  -v /data/redis/data:/data \
  -v /data/redis/log:/var/log/redis \
  --restart=always \
  redis redis-server --requirepass '!QA2ws3ed'

nginx

拉取镜像

docker pull nginx

创建映射文件夹

mkdir -p /data/nginx/{conf,html,log}

创建容器 并copy 配置文件

#生成容器
docker run --name nginx -p 9001:80 -d nginx
#将容器nginx.conf文件复制到宿主机
docker cp nginx:/etc/nginx/nginx.conf /data/nginx/conf/nginx.conf
#将容器conf.d文件夹下内容复制到宿主机
docker cp nginx:/etc/nginx/conf.d /data/nginx/conf/conf.d
#将容器中的html文件夹复制到宿主机
docker cp nginx:/usr/share/nginx/html /data/nginx/

卸载镜像

docker stop nginx
docker rm nginx

安装镜像

docker run -p 80:80 --name nginx \
-v /data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf  \
-v /data/nginx/conf/conf.d:/etc/nginx/conf.d  \
-v /data/nginx/log:/var/log/nginx  \
-v /data/nginx/html:/usr/shard/nginx/html -d \
--restart=always \
nginx

在/data/nginx/conf/conf.d下创建jenkins.conf

# 定义一个名为 jenkins_upstream 的上游服务器组
server {
    listen 80;

    server_name jenkins.yych.me;

    # 访问日志配置
    access_log /var/log/nginx/jenkins.access.log;
    error_log /var/log/nginx/jenkins.error.log;
    
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # SSL 配置(如果需要的话)
    # listen 443 ssl;
    # ssl_certificate /etc/nginx/ssl/myjdyun.com.crt;
    # ssl_certificate_key /etc/nginx/ssl/myjdyun.com.key;
    # ssl_protocols TLSv1.2 TLSv1.3;
    # ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256...';
    # ssl_prefer_server_ciphers on;

    # HSTS 配置(如果需要的话)
    # add_header Strict-Transport-Security "max-age=31536000" always;

    # 设置客户端请求体大小限制
    client_max_body_size 100m;
    client_body_buffer_size 100k;
    
     # 设置代理连接的超时时间
    proxy_connect_timeout 60s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;

    # 设置根目录(如果需要的话)
    # root /usr/share/nginx/html;

    location / {
        proxy_pass http://192.168.0.16:9080;
        add_header Strict-Transport-Security "max-age=31536000";
    }

    # 如果需要,可以添加更多的 location 块来处理特定的路径或文件类型

    # 错误页面配置
    error_page 404 /404.html;
    location = /404.html {
        root /usr/share/nginx/html;
        internal;
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}

重启nginx

docker restart  nginx