前端集成化部署 docker篇

Docker的由來

咱們可能會遇到這樣的問題,咱們手動部署項目,多是node項目,多是java項目,多是前端項目,咱們安裝的node版本或者jdk,tomcat版本不一致,致使項目會發生各類詭異問題,有的服務器就是好使,有的服務器就是有問題,正常來講都是部署漏了點東西。
咱們就不能把好的服務打成包直接拿來使用麼?html

佈署軟件的問題

  • 若是想讓軟件運行起來要保證操做系統的設置,各類庫和組件的安裝都是正確的
  • 熱帶魚&冷水魚 冷水魚適應的水溫在5-30度,而熱帶魚只能適應22-30度水溫,低於22度半小時就凍死了

經常使用解決方案和對比

虛擬機

虛擬機(virtual machine)就是帶環境安裝的一種解決方案。它能夠在一種操做系統裏面運行另外一種操做系統前端

  • 資源佔用多
  • 冗餘步驟多
  • 啓動速度慢

Linux容器

因爲虛擬機存在這些缺點,Linux 發展出了另外一種虛擬化技術:Linux 容器(Linux Containers,縮寫爲 LXC)。
Linux 容器不是模擬一個完整的操做系統,而是對進程進行隔離。或者說,在正常進程的外面套了一個保護層。對於容器裏面的進程來講,它接觸到的各類資源都是虛擬的,從而實現與底層系統的隔離。java

  • 啓動快
  • 資源佔用少
  • 體積小

Docker

  • Docker 屬於 Linux 容器的一種封裝,提供簡單易用的容器使用接口。它是目前最流行的 Linux 容器解決方案。
  • Docker 將應用程序與該程序的依賴,打包在一個文件裏面。運行這個文件,就會生成一個虛擬容器。程序在這個虛擬容器裏運行,就好像在真實的物理機上運行同樣

Docker和KVM

  1. 啓動時間
  • Docker秒級啓動
  • KVM分鐘級啓動
  1. 輕量級 容器鏡像一般以M爲單位,虛擬機以G爲單位,容器資源佔用小,要比虛擬要部署更快速
  • 容器共享宿主機內核,系統級虛擬化,佔用資源少,容器性能基本接近物理機
  • 虛擬機須要虛擬化一些設備,具備完整的OS,虛擬機開銷大,於是下降性能,沒有容器性能好
  1. 安全性
  • 因爲共享宿主機內核,只是進程隔離,所以隔離性和穩定性不如虛擬機,容器具備必定權限訪問宿>- 主機內核,存在一下安全隱患
  1. 使用要求
  • KVM基於硬件的徹底虛擬化,須要硬件CPU虛擬化技術支持
  • 容器共享宿主機內核,可運行在主機的Linux的發行版,不用考慮CPU是否支持虛擬化技術

Docker的應用場景

  • 節省項目環境部署時間
  • 單項目打包
  • 整套項目打包
  • 新開源技術
  • 環境一致性
  • 持續集成
  • 微服務
  • 彈性伸縮

Docker 體系結構

  • containerd 是一個守護進程,使用runc管理容器,向Docker Engine提供接口
  • shim 只負責管理一個容器
  • runC是一個輕量級工具,只用來運行容器

Docker安裝

安裝社區版本docker
yum install -y yum-utils   device-mapper-persistent-data   lvm2
yum-config-manager     --add-repo     https://download.docker.com/linux/centos/docker-ce.repo
yum-config-manager --enable docker-ce-nightly #要每日構建版本的 Docker CE
yum-config-manager --enable docker-ce-test  
yum install docker-ce docker-ce-cli containerd.io
複製代碼

docker 啓動node

systemctl start docker
複製代碼

查看docker版本mysql

docker version
docker info
複製代碼

鏡像加速

阿里雲鏡像加速linux

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://fwvjnv59.mirror.aliyuncs.com"]
}
EOF
# 重載全部修改過的配置文件
sudo systemctl daemon-reload
sudo systemctl restart docker
複製代碼

Docker經常使用方法

docker image鏡像操做nginx

命令 含義 案例
ls 查看所有鏡像 docker image ls
search 查找鏡像 docker search [imageName]
history 查看鏡像歷史 docker history [imageName]
inspect 顯示一個或多個鏡像詳細信息 docker inspect [imageName]
pull 拉取鏡像 docker pull [imageName]
push 推送一個鏡像到鏡像倉庫 docker push [imageName]
rmi 刪除鏡像 docker rmi [imageName] docker image rmi 2
prune 移除未使用的鏡像,沒有被標記或補任何容器引用 docker image prune
tag 標記本地鏡像,將其納入某一倉庫 docker image tag [imageName] [username]/[repository]:[tag]
export 導出容器文件系統tar歸檔文件建立鏡像 docker export -o mysqlv1.tar a404c6c174a2
import 導入容器快照文件系統tar歸檔文件建立鏡像 docker import mysqlv1.tar wp/mysql:v2
save 保存一個或多個鏡像到一個tar歸檔文件 docker save -o mysqlv2.tar wp/mysqlv2:v3
load 加載鏡像存儲文件來自tar歸檔或標準輸入 docker load -i mysqlv2.tar
build 根據Dockerfile構建鏡像

docker 容器操做git

命令 含義 案例
run 從鏡像運行一個容器 docker run ubuntu /bin/echo 'hello-world'
ls 列出容器 docker container ls
inspect 顯示一個或多個容器詳細信息 docker inspect
attach 要attach上去的容器必須正在運行,能夠同時鏈接上同一個container來共享屏幕 docker attach
stats 顯示容器資源使用統計 docker container stats
top 顯示一個容器運行的進程 docker container top
update 顯示一個容器運行的進程 docker container update
port 更新一個或多個容器配置 docker container port
ps 查看當前運行的容器 docker ps -a -l
kill [containerId] 終止容器(發送SIGKILL ) docker kill [containerId]
rm [containerId] 刪除容器 docker rm [containerId]
start [containerId] 啓動已經生成、已經中止運行的容器文件 docker start [containerId]
stop [containerId] 終止容器運行 (發送 SIGTERM ) docker stop [containerId]
logs [containerId] 查看 docker 容器的輸出 docker logs [containerId]
exec [containerId] 進入一個正在運行的 docker 容器執行命令 docker container exec -it [containerID] /bin/bash
cp [containerId] 從正在運行的 Docker 容器裏面,將文件拷貝到本機 docker container cp [containID]:app/package.json .
commit [containerId] 建立一個新鏡像來自一個容器 docker commit -a "wp" -m "mysql" a404c6c174a2 mynginx:v1

docker 數據盤操做github

  • volume
#建立數據盤
docker volume create nginx-vol
docker volume ls
docker volume inspect nginx-vol
#把nginx-vol數據卷掛載到/usr/share/nginx/html,掛載後容器內的文件會同步到數據卷中
docker run -d  --name=nginx1 --mount src=nginx-vol,dst=/usr/share/nginx/html nginx
docker run -d  --name=nginx2  -v nginx-vol:/usr/share/nginx/html -p 3000:80 nginx
#刪除數據卷
docker container stop nginx1 #中止容器
docker container rm nginx1 #刪除容器
docker volume rm nginx-vol  #刪除數據庫
複製代碼
  • Bind mounts
#此方式與Linux系統的mount方式很類似,便是會覆蓋容器內已存在的目錄或文件,但並不會改變容器內原有的文件,當umount後容器內原有的文件就會還原
#建立容器的時候咱們能夠經過-v或--volumn給它指定一下數據盤
#bind mounts 能夠存儲在宿主機系統的任意位置
#若是源文件/目錄不存在,不會自動建立,會拋出一個錯誤
#若是掛載目標在容器中非空目錄,則該目錄現有內容將被隱藏
docker run -v /mnt:/mnt -it --name logs centos bash
cd /mnt
echo 1 > 1.txt
docker inspect logs
#能夠查看到掛載信息
"Mounts": [
    {
        "Source":"/mnt/sda1/var/lib/docker/volumes/dea6a8b3aefafa907d883895bbf931a502a51959f83d63b7ece8d7814cf5d489/_data",
        "Destination": "/mnt",
    }
]
# 指定數據盤容器
docker create -v /mnt:/mnt --name logger centos
docker run --volumes-from logger --name logger3 -i -t centos bash
cd /mnt 
touch logger3
docker run --volumes-from logger --name logger4 -i -t centos bash
cd /mnt
touch logger4
複製代碼

docker 網絡
安裝Docker時,它會自動建立三個網絡,bridge(建立容器默認鏈接到此網絡)、 none 、hostweb

  • None:該模式關閉了容器的網絡功能,對外界徹底隔離
  • host:容器將不會虛擬出本身的網卡,配置本身的IP等,而是使用宿主機的IP和端口。
  • bridge 橋接網絡,此模式會爲每個容器分配IP
    可使用該--network標誌來指定容器應鏈接到哪些網絡
#bridge模式使用 --net=bridge 指定,默認設置
docker network ls #列出當前的網絡
docker inspect bridge #查看當前的橋連網絡
docker run -d --name nginx1 nginx
docker run -d --name nginx2 --link nginx1 nginx
docker exec -it nginx2 bash
apt update
apt install -y inetutils-ping  #ping
apt install -y dnsutils        #nslookup
apt install -y net-tools       #ifconfig
apt install -y iproute2        #ip
apt install -y curl            #curl
cat /etc/hosts
ping nginx1

# none模式使用--net=none指定
# --net 指定無網絡
docker run -d --name nginx_none --net none nginx
docker inspect none
docker exec -it nginx_none bash
ip addr

# host模式使用 --net=host 指定
docker run -d --name nginx_host --net host nginx
docker inspect host
docker exec -it nginx_host bash
ip addr
複製代碼

端口映射

# 查看鏡像裏暴露出的端口號
docker image inspect nginx
"ExposedPorts": {"80/tcp": {}}
# 讓宿主機的8080端口映射到docker容器的80端口
docker run -d --name port_nginx -p 8080:80  nginx
# 查看主機綁定的端口
docker container port port_nginx

#指向主機的隨機端口
docker run -d --name random_nginx --publish 80 nginx
docker port random_nginx

docker run -d --name randomall_nginx --publish-all nginx
docker run -d --name randomall_nginx --P nginx

#建立自定義網絡
docker network create --driver bridge myweb
# 查看自定義網絡中的主機
docker network inspect myweb
# 建立容器的時候指定網絡 指定同一個網絡的容器是能夠互相通訊的
docker run -d --name mynginx1  --net myweb nginx
docker run -d --name mynginx2  --net myweb nginx
docker exec -it mynginx2 bash
ping mynginx1

# 鏈接到指定網絡
docker run -d --name mynginx3   nginx
docker network connect  myweb mynginx3
docker network disconnect myweb mynginx3

# 移除網絡
docker network rm myweb
複製代碼

compose 暫時先不說,暫時用到的很少,主要作編排使用,基本上都在使用jekins作編排

部署環境

node環境部署

安裝完docker環境 繼續安裝node環境

nvm: # nvm管理node版本
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh | bash
source ~/.bash_profile
nvm ls
nvm install stable 安裝最新的穩定版本
nvm use stable
nrm:# 切換node鏡像,修改源爲淘寶鏡像
npm i -g nrm
nrm use taobao
複製代碼

安裝pm2 部署線上 node服務

npm i -g pm2
cd /root/webhook
pm2 start webhook.js --name webhook --watch
pm2 list | pm2 ls
複製代碼

集成項目搭建

回想起之前的前端部署都是前端打個目標文件,壓縮成壓縮包或者rpm安裝包去發佈,若是有多個環境還須要一步步的去連服務器去手動發佈
爲了解決這種耗人力的工做,這邊推出了一款簡易的docker發佈項目
咱們能夠把其中一臺服務器配置成發佈服務器,用來編譯新鏡像發佈新鏡像,而後直接拷貝鏡像到別的服務器直接啓動

如今咱們見一個node項目 docker-hook
此項目的核心是經過用戶點擊頁面上的觸發去動態調用sh去處理咱們的腳本
中間一版本咱們是經過接口調用觸發,發現不是很好用,就作一個可視化平臺去使用
也能夠經過gitHub的webhook去動態觸發CI/CD,提交即部署,這邊我就不貼代碼了
這邊主要講思路,貼上部分代碼,若是有須要優化的部分麻煩指正

// 本項目使用的是經過node的child_process spawn開啓一個子進程去處理sh命令
// console log日誌是經過morgan 自定義輸出
// 每一個模塊的sh腳本都會經過winston把實時日誌存儲到對應的模塊日誌文件中,文件大問題,咱們就按天生成一個文件日誌
/** logger.js **/
const winston=require('winston');
const { APP_LIST } = require('./constant')
const { loggerTime } = require('./util')

const loggerList = {};
APP_LIST.forEach(item => {
  loggerList[item.loggerName] = winston.createLogger({
    transports: [
        new (winston.transports.Console)(),
        new (winston.transports.File)({ 
            filename: `public/logs/${item.loggerName}-${loggerTime()}.log`,
            timestamp:'true', 
            maxsize: 10485760, //日誌文件的大小
            maxFiles: 10 })
    ]});
});
loggerList['init'] = winston.createLogger({
  transports: [
      new (winston.transports.Console)(),
      new (winston.transports.File)({ 
          filename: `public/logs/init-${loggerTime()}.log`,
          timestamp:'true', 
          maxsize: 10485760, //日誌文件的大小
          maxFiles: 10 })
  ]});

module.exports = loggerList;

/** app.js **/
let { spawn } = require('child_process');
/** * 統一處理shell腳本執行 */
function handleShellFile(projectName, shellPath, res, req) {
  return resolveFile(shellPath).then(data => {
    // 判斷當前是不是成功
    if(!data.success) {
      errorHandle(res);
    }
    let child = spawn('sh', [data.filePath])
    let buffers = [];
    child.stdout.on('data', (buffer) => {
      buffers.push(buffer);
      console.log('實時日誌:', buffer.toString());
      logger[projectName] && logger[projectName].log("info", `實時日誌:${buffer.toString()}`);
    })
    child.stdout.on('end',function(buffer){
      let logs = Buffer.concat(buffers, buffer).toString();
      console.log('執行完畢');
      logger[projectName] && logger[projectName].log("info", '執行完畢');
      res.setHeader('Content-Type', 'application/json');
      res.end(JSON.stringify({ok: true}))
    });
    child.on('close', (code) => {
      if (code !== 0) {
        console.log(`子進程退出,退出碼 ${code}`);
      }
    });
  }, error => {
    // 錯誤處理顯示返回
    errorHandle(res);
  })
}
複製代碼

shell文件介紹:

├─ docker-hook
│  ├─ sh // shell腳本文件
│  │  ├─ Archer-front-image.sh // 前端版本複製鏡像
│  │  ├─ Archer-front-remote.sh // 前端版本遠程打包
│  │  ├─ Archer-front.sh // 前端版本本地打包編譯發佈(本地使用)
│  │  ├─ ar-mock-image.sh // armock項目複製鏡像
│  │  ├─ ar-mock-remote.sh // armock項目遠程打包
│  │  ├─ ar-mock.sh // armock項目本地打包編譯發佈(本地使用)
│  │  ├─ env-init.sh // 環境初始化
│  │  └─ project-init.sh // git項目初始化,幫忙建目錄
複製代碼

env-init.sh 能夠拷貝到服務器 一鍵去部署環境

#!/bin/bash
echo 'docker 環境初始化'
function docker_install()
{
	echo "檢查Docker......"
	docker -v
  if [ $? -eq  0 ]; then
      echo "檢查到Docker已安裝!"
  else
      echo "安裝docker環境..."
      yum install -y yum-utils   device-mapper-persistent-data   lvm2
      yum-config-manager     --add-repo     https://download.docker.com/linux/centos/docker-ce.repo
      yum-config-manager --enable docker-ce-nightly #要每日構建版本的 Docker CE
      yum-config-manager --enable docker-ce-test  
      yum install -y docker-ce docker-ce-cli containerd.io

      echo '啓動docker'
      systemctl start docker

      echo '查看docker'
      docker version
      echo "安裝docker環境...安裝完成!"
  fi
}
# 執行函數
docker_install

# nrm 是否安裝
function nvm_install()
{
	nvm --version
    if [ $? -eq  0 ]; then
       echo "檢查到nvm已安裝!"
       nvm install v13.14.0 #安裝最新的穩定版本
       nvm use v13.14.0
       echo "安裝node環境...安裝完成!"
    else
      source /root/.bashrc
    	echo "安裝nvm失敗..."
    fi
}

# node 是否安裝
function node_install()
{
	echo "檢查node......"
	node -v
    if [ $? -eq  0 ]; then
        echo "檢查到Node已安裝!"
    else
    	echo "安裝nvm環境..."
       curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh | bash
       source /root/.bashrc
       nvm_install
    fi
}

# node_module庫 安裝監測
function node_module_install()
{
	  node --version
    if [ $? -eq  0 ]; then
      echo "安裝nrm源和pm2庫"
      nrm_install
      pm2_install
    else
    	echo "node環境未安裝成功"
    fi
}

# nrm 安裝監測
function nrm_install()  {
    echo "監測nrm源..."
    nrm --version
    if [ $? -eq 0 ]; then
    echo "已安裝nrm源"
    else 
    npm i -g nrm
    nrm use taobao
    echo "安裝nrm源成功"
    fi
}

# pm2 安裝監測
function pm2_install()  {
    echo "監測pm2庫..."
    pm2 --version
    if [ $? -eq  0 ]; then
    echo "已安裝pm2庫"
    else 
    npm i -g pm2
    echo "安裝pm2庫成功"
    fi
}
 
# 執行函數
echo '安裝node環境'
node_install
node_module_install
複製代碼

# 若是已經安裝過node,確認下是否更新過~/.bash_profile,沒有則添加,也能夠安裝nvm去管理node export NODE_ENV=/root/node/node-v12.16.2-linux-x64 PATH=$PATH:$HOME/bin:$NODE_ENV/bin 刷新配置文件 source ~/.bash_profile

project.sh 文件主要是創建文件目錄,git clone文件併爲後續的部署作準備

Archer-front.sh 拉代碼部署,鏡像生成,容器部署一個文件搞定

#!/bin/bash
WORK_PATH='/root/front'
cd $WORK_PATH
echo "清除老代碼"
git reset --hard origin/master
git clean -f
echo "拉取最新代碼"
git pull origin master
echo "刪除node_modules文件"
rm -rf ./node_modules
echo "從新安裝依賴"
npm i
echo "編譯打包"
npm run build
echo "開始執行構建"
docker build -f ./docker/Dockerfile -t archer-front:1.0 .
echo "中止舊的容器並刪除容器"
docker stop archer-front-container
docker rm archer-front-container
echo "啓動新容器"
docker run -p 11001:11001 -v /etc/hosts:/etc/hosts --name archer-front-container -itd archer-front:1.0
複製代碼

那麼多節點部署怎麼辦呢?
咱們能夠考慮把當前的這個鏡像導出並導入加載
Archer-front-image.sh

#!/bin/bash
echo "進入目錄/root/images"
WORK_PATH='/root'
cd $WORK_PATH
if [ ! -d images  ];then
  mkdir images
fi
IMAGES_PATH='images'
cd $IMAGES_PATH
echo "開始拷貝前端鏡像"
docker save -o image-Archer-front.tar archer-front:1.0
echo "拷貝前端鏡像完成"
複製代碼

其餘節點怎麼來拿呢?能夠經過scp來拷貝這邊打包出來的鏡像去使用啊,這就是Archer-front-remote.sh裏面的實現

查看日誌功能主要是經過定時刷新調用接口去實現的,有些low,本身使用不會有那麼大的量,因此沒走實時刷新。
咱們再來看看效果,是否是很香。

一次發佈,終身好用
相關文章
相關標籤/搜索