# 初探 DEVOPS 本地 CICD 部屬
怎麼麼說呢,在上一章 的 到 部屬到 GCP 的 CICD ,這假設在一年的前端在大陸地區落地計畫肯定是行不通的,那麼我們可能就要採用 私有 本地的方式架設 CICD
可以學習到
* docker & docker-compose
* gitlab
* Drone
* Kubernetes
詳細相關概念參考與實作 https://ithelp.ithome.com.tw/users/20120491/ironman/2538?page=3
主要我們是要針對 我們的 vue 和 spring cloud 做一個 部屬的動作所以 中間使用 golang 的片段 可能會被改成 nodejs 部分
那麼我們開始簡化上述文章做一個整理。
# Docker
簡單執行一個 container
>docker run -d nginx
類似工作管理員 可以看目前執行的 container
>docker ps -a
>
讓你的 container 有名字
> docker run -d --name=nginx nginx
>
暴露端口到本地 因為我們適用 wsl 所以 這樣的意思就是直接讓畚箕 8081 指向容器內 80 端口
>docker run -d --name=nginx -p 8081:80 nginx
容器外檔案指向外部
假設有一
index.html
建立於根目錄
```html
<h1>1234</h1>
```
>docker run -d --name=nginx -p 8081:80 -v "$(pwd)/index.html:/usr/share/nginx/html/index.html" nginx
>
這樣意思就是
-v "$(pwd)/index.html:/usr/share/nginx/html/index.html
本機目錄 index.html 映射到 /usr/share/nginx/html/index.html
## 安裝 Pontainer
這個是主要來管理 docker 容器的 ,第一次進入請 選 local


>docker run -d -p 9000:9000 --name portainer --restart always -v /var/run/docker.sock:/var/run/docker.sock -v /home/Portainer:/data portainer/portainer
可以觀看 執行中的 container

# Docker-Composr
以 docker-compose.yml 方式改寫我們的 nginx 範本
## add docker-compose.yml
```yml
version: '3' # 目前使用的版本
services: # services 固定字
web: # 可以隨機命名,識別用
image: nginx:1.12.1 # image 容器 + 版本號
container_name: nginx-servie # 容器名稱
restart: always # 當機器重新啟動時,服務會自動啟動
ports: # 容器外與容器內的Port
- 8081:80
volumes: # 將容器外檔案掛載至容器內,如果容器內相同路徑已經存在相同檔案,則會覆蓋內容
- ./default.conf:/etc/nginx/conf.d/default.conf
- ./index.html:/home/project/index.html
```
## add default.conf
```conf
server {
listen 80;
server_name localhost;
location / {
root /home/project;
index index.html index.htm;
}
}
```
## add index.html
```html
<h1>1234</h1>
```
啟動
> docker-compose up -d
>
## container 溝通
以範例來說,下面例子我隨便舉 反正就是兩個 docker-compose 互通網段 關鍵在 networks
## docker-compose.yml 1
```yml
version: '3' # 目前使用的版本
services: # services 固定字
web: # 可以隨機命名,識別用
image: nginx:1.12.1 # image 容器 + 版本號
container_name: nginx-servie # 容器名稱
restart: always # 當機器重新啟動時,服務會自動啟動
ports: # 容器外與容器內的Port
- 8081:80
volumes: # 將容器外檔案掛載至容器內,如果容器內相同路徑已經存在相同檔案,則會覆蓋內容
- ./default.conf:/etc/nginx/conf.d/default.conf
- ./index.html:/home/project/index.html
# 表示服務用的網絡是用外部的網路,並且搜尋名稱為「web_service」
# 若搜尋失敗,則會顯示該錯誤
# ERROR: Please create the network manually using `docker network create web_services` and try again.
networks:
web_service:
external: true
```
## docker-compose.yml 2
```yml
version: '3' # 目前使用的版本
services: # services 固定字
web: # 可以隨機命名,識別用
image: nginx:1.12.1 # image 容器 + 版本號
container_name: nginx-servie # 容器名稱
restart: always # 當機器重新啟動時,服務會自動啟動
ports: # 容器外與容器內的Port
- 8081:80
volumes: # 將容器外檔案掛載至容器內,如果容器內相同路徑已經存在相同檔案,則會覆蓋內容
- ./default.conf:/etc/nginx/conf.d/default.conf
- ./index.html:/home/project/index.html
# 表示服務用的網絡是用外部的網路,並且搜尋名稱為「web_service」
# 若搜尋失敗,則會顯示該錯誤
# ERROR: Please create the network manually using `docker network create web_services` and try again.
networks:
web_service:
external: true
```
因為照理來說container 建立的時候

ip會自動遞增 , 那麼假設 我們要在同一個 docker-compose 去共用一個網段怎麼辦呢
## web_service 表示該段名稱
> docker network create web_service
## 建置完畢後,可以透過以下指令查看
> docker network ls
>

## docker-compose example
```yml
version: "3" # docker-compose 版本號
services: # 開始撰寫 container 服務
redis: # 可以隨意命名,通常以有意義的字串命名
image: redis:5.0.5-alpine # 服務容器,若無指定版號表示使用 latest 版本, alpine 容器佔用空間較小,通常建議使用
volumes: # 掛載的撰寫方式,如果有多組不同路徑掛載,只需要在新增幾行條件即可。
- ./redis.conf:/usr/local/etc/redis/redis.conf
container_name: myredis # 指容器名稱,這裡比較不同的是指令使用「--name」,但在yml應該使用「container_name」
command: redis-server /usr/local/etc/redis/redis.conf # command 表示啟動容器後預備執行的動作
environment: # 提供參數至容器內部,docker 指令是使用「-e 或者 --env」,但在yml應該使用「environment」 反正就是環境變數
- ENV=develop
```
# Custom 自定義 docker image
假設我們要 重寫 在網上一個 發布的 container 額外增加其他 功能呢我們可以用到 dockerfile
## add Dockerfile
```Dockerfile
Dockerfile:
# 以 nginx 1.12.1 的版本作為基底
FROM nginx:1.12.1 AS builder
# Install logrotate
# RUN 指令可以協助安裝套件或者執行否些指令
RUN apt-get update && apt-get -y install logrotate
# 將logroate規則複製進容器(必須讓檔案為root用戶,才可以執行)
# COPY 指令可以協助將容器外部的檔案,複製到容器內某路徑
COPY ./nginx-logrotate /etc/logrotate.d/nginx
# CDM 指令指容器啟動後,需要做的行為
# 該範例為啟動 cron 背景服務 + nginx 服務
CMD service cron start && nginx -g 'daemon off;'
```
## add default.conf
```default.conf
server {
listen 80;
server_name localhost;
location / {
root /home/project;
index index.html index.htm;
}
}
```
## add index.html
```html
<h1>1234</h1>
```
## nginx-logrotate
```
/var/log/nginx/*.log {
daily
missingok
rotate 7
compress
dateext
notifempty
create
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}
```
## docker-compose.yml
```yml
version: '3'
services:
web:
build:
context: . # 讀取當前路徑的 Dockerfile
restart: always # 虛擬機會實體機重起後,容器服務自動帶起
container_name: nginx # 容器名稱
volumes:
- ./default.conf:/etc/nginx/conf.d/default.conf # 掛載 nginx 設定檔,可自由操控nginx設定檔
- ./index.html:/home/project/index.html # 掛載專案
working_dir: /home/project # 進入容器後的預設路徑
ports: # 容器內與容器外 Port
- 8899:80
networks: # 指定使用那一條網路
- web_service
# 表示服務用的網絡是用外部的網路,並且搜尋名稱為 「web_service」
# 搜尋成功後會自動與「webs」服務相連
networks:
web_service:
external: true
```
以上即可完成 nginx 服務建置。
# build 成 image
在推上 docker hub 或者私有 harbor (私有庫) 保存,日後直接使用
# 將 Dockerfile build 成 image 並加上 tag
> docker build -t x213212/nginx:1.12.1 .
> -t 表示替 image 打上 tag
> 因為接下來示範將 images 推至 docker hub
> 故 image tag 直接使用個人的 x213212/nginx (專案名稱) + 1.12.1 (版本號)
>
# 檢查是否 build 成功
>docker images | grep "x213212/nginx"
# 推至公開的 docker hub
> docker push x213212/nginx:1.12.1