用 Docker 到會(huì)造 Docker:從零到企業(yè)級(jí)部署)
第六章Dockerfile從會(huì)用 Docker 到會(huì)造 Dockerdocker基礎(chǔ)到這里你已經(jīng)掌握Image 鏡像 ↓ Container 容器 ↓ Volume 數(shù)據(jù) ↓ Network 網(wǎng)絡(luò)但是現(xiàn)在你還是主要在用別人做好的鏡像docker pull nginx docker pull mysql docker pull redis真正開(kāi)發(fā)工作中公司自己的項(xiàng)目怎么辦比如你的項(xiàng)目商城系統(tǒng) ├── Java代碼 ├── 配置文件 ├── 依賴(lài) └── 啟動(dòng)腳本怎么變成company-shop:v1然后服務(wù)器docker run company-shop:v1直接運(yùn)行答案Dockerfile。1. Dockerfile 是什么一句話(huà)Dockerfile 是制作 Docker 鏡像的說(shuō)明書(shū)。比如做蛋糕普通人買(mǎi)蛋糕Docker自己寫(xiě)配方 ↓ 制作蛋糕Dockerfile就是配方。例如DockerfileFROM ubuntu RUN apt update RUN apt install nginx COPY index.html /var/www/html/ CMD [nginx,-g,daemon off;]意思從 Ubuntu 開(kāi)始 安裝 nginx 復(fù)制網(wǎng)頁(yè) 啟動(dòng) nginx然后生成鏡像my-web:v12. Dockerfile 工作流程完整流程代碼 | | ↓ Dockerfile | | ↓ docker build | | ↓ Image 鏡像 | | ↓ docker run | | ↓ Container3. 創(chuàng)建第一個(gè) Dockerfile準(zhǔn)備目錄my-nginx/ ├── Dockerfile └── index.htmlindex.htmlh1Hello Docker/h1DockerfileFROM nginx COPY index.html /usr/share/nginx/html/解釋FROM基礎(chǔ)鏡像。格式FROM 鏡像名例如FROM nginx意思基于 nginx 制作。類(lèi)似站在別人肩膀上開(kāi)發(fā)COPY復(fù)制文件。格式COPY 本地文件 容器路徑例如COPY index.html /usr/share/nginx/html/結(jié)果容器里面/usr/share/nginx/html/index.html4. 構(gòu)建鏡像進(jìn)入目錄cd my-nginx執(zhí)行docker build -t my-nginx:v1 .解釋build創(chuàng)建鏡像。-ttag。例如-t my-nginx:v1名字my-nginx 版本 v1.當(dāng)前目錄。Docker 會(huì)尋找./Dockerfile構(gòu)建過(guò)程你會(huì)看到Step 1/2 FROM nginx Step 2/2 COPY index.html成功Successfully built abc123查看docker images出現(xiàn)my-nginx v15. 運(yùn)行自己制作的鏡像啟動(dòng)docker run \ -d \ -p 8080:80 \ my-nginx:v1訪(fǎng)問(wèn)localhost:8080看到Hello Docker成功。你第一次造出了自己的鏡像。6. Dockerfile 常用指令大全Dockerfile 最重要的幾個(gè)FROM RUN COPY ADD WORKDIR ENV EXPOSE CMD ENTRYPOINT下面逐個(gè)講。7. FROM基礎(chǔ)鏡像。必須第一行。例如PythonFROM python:3.12JavaFROM openjdk:17NodeFROM node:20選擇基礎(chǔ)鏡像開(kāi)發(fā)ubuntu debian生產(chǎn)alpine slim例如推薦FROM python:3.12-slim不要FROM ubuntu然后自己安裝 Python。浪費(fèi)空間。8. RUN執(zhí)行 Linux 命令。例如RUN apt update安裝RUN apt install -y nginx例如FROM ubuntu RUN apt update RUN apt install -y curl構(gòu)建時(shí)執(zhí)行。不是運(yùn)行容器時(shí)執(zhí)行。9. RUN 合并優(yōu)化錯(cuò)誤RUN apt update RUN apt install nginx RUN apt clean會(huì)產(chǎn)生很多層。優(yōu)化RUN apt update \ apt install -y nginx \ apt clean減少鏡像大小。10. COPY復(fù)制文件。例如項(xiàng)目app/ ├── Dockerfile └── app.pyDockerfileCOPY app.py /app/結(jié)果容器/app/app.py11. WORKDIR設(shè)置工作目錄。例如WORKDIR /app之后COPY app.py .等于COPY app.py /app/推薦不要RUN cd /app因?yàn)橄乱粚邮?。使用WORKDIR /app12. ENV設(shè)置環(huán)境變量。例如ENV PORT8080容器里面echo $PORT輸出8080常見(jiàn)數(shù)據(jù)庫(kù)MYSQL_ROOT_PASSWORD程序JAVA_OPTS13. EXPOSE聲明端口。例如EXPOSE 8080注意它不會(huì)真正打開(kāi)端口。真正需要-p例如docker run -p 8080:8080 app14. CMD非常重要指定容器啟動(dòng)后執(zhí)行什么。例如CMD [python,app.py]容器啟動(dòng)自動(dòng)python app.py例如Python項(xiàng)目DockerfileFROM python:3.12 WORKDIR /app COPY app.py . CMD [python,app.py]運(yùn)行docker run my-python自動(dòng)python app.py15. ENTRYPOINT和 CMD 很像。區(qū)別CMD容易被覆蓋。ENTRYPOINT固定執(zhí)行。例如ENTRYPOINT [python] CMD [app.py]運(yùn)行docker run image執(zhí)行python app.py運(yùn)行docker run image test.py執(zhí)行python test.py16. CMD 和 ENTRYPOINT 區(qū)別記憶ENTRYPOINT 主程序 CMD 默認(rèn)參數(shù)例如ENTRYPOINT python CMD app.py組合python app.py17. 一個(gè)真實(shí) Python 項(xiàng)目 Dockerfile項(xiàng)目my-api ├── app.py ├── requirements.txt └── Dockerfilerequirementsflask requestsDockerfileFROM python:3.12-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY app.py . EXPOSE 5000 CMD [python,app.py]構(gòu)建docker build -t my-api:v1 .運(yùn)行docker run \ -d \ -p 5000:5000 \ my-api:v118. 鏡像分層和緩存高手必須懂DockerfileFROM python COPY requirements.txt . RUN pip install -r requirements.txt COPY code .為什么這樣寫(xiě)因?yàn)镈ocker緩存。第一次安裝依賴(lài) 復(fù)制代碼第二次改代碼Docker發(fā)現(xiàn)requirements沒(méi)變。所以不用重新安裝。速度快。錯(cuò)誤寫(xiě)法COPY . . RUN pip install -r requirements.txt每次代碼變化重新安裝依賴(lài)。慢。19. 多階段構(gòu)建高級(jí)生產(chǎn)非常常見(jiàn)。例如Java項(xiàng)目第一階段編譯JDK 源碼 jar第二階段運(yùn)行JRE jar結(jié)構(gòu)階段1 maven ↓ 生成 jar 階段2 jdk小鏡像 ↓ 運(yùn)行jar優(yōu)勢(shì)鏡像巨大減少。20. 企業(yè) Dockerfile 標(biāo)準(zhǔn)思路通常1. 選擇小基礎(chǔ)鏡像 2. 固定版本 3. 設(shè)置WORKDIR 4. 先復(fù)制依賴(lài) 5. 安裝依賴(lài) 6. 再?gòu)?fù)制代碼 7. 設(shè)置啟動(dòng)命令 8. 不使用root用戶(hù)21. 常見(jiàn)錯(cuò)誤錯(cuò)誤1Dockerfile名字錯(cuò)誤dockerfile應(yīng)該Dockerfile大小寫(xiě)敏感。錯(cuò)誤2COPY路徑錯(cuò)誤例如COPY app.py /app但是文件不在當(dāng)前目錄。錯(cuò)誤3容器啟動(dòng)馬上退出原因CMD執(zhí)行完結(jié)束。例如錯(cuò)誤CMD [echo,hello]輸出hello然后容器退出。本章核心命令功能命令構(gòu)建鏡像docker build查看鏡像docker images查看構(gòu)建歷史docker history刪除鏡像docker rmi運(yùn)行鏡像docker run第七章Docker Compose多容器項(xiàng)目管理神器到現(xiàn)在你已經(jīng)會(huì)? 拉鏡像? 創(chuàng)建容器? 數(shù)據(jù)持久化? 容器網(wǎng)絡(luò)? 制作自己的鏡像但是你會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題真實(shí)項(xiàng)目不是一個(gè)容器。例如一個(gè)電商網(wǎng)站用戶(hù) | ↓ Nginx容器 | ↓ Java后端容器 | ----------------- | | ↓ ↓ MySQL容器 Redis容器如果不用 Compose你可能需要docker run nginx ... docker run java ... docker run mysql ... docker run redis ...幾十個(gè)參數(shù)。非常痛苦。Docker Compose 解決用一個(gè)配置文件管理整個(gè)應(yīng)用。1. Docker Compose 是什么一句話(huà)Docker Compose 是用 YAML 文件描述多個(gè) Docker 容器然后一鍵啟動(dòng)、停止、管理整個(gè)系統(tǒng)。以前docker run ... docker run ... docker run ...現(xiàn)在docker compose up全部啟動(dòng)。2. Compose 的核心文件名字docker-compose.yml例如services: nginx: mysql: redis:它描述有哪些服務(wù)使用什么鏡像端口網(wǎng)絡(luò)數(shù)據(jù)卷環(huán)境變量3. 第一個(gè) Compose 示例創(chuàng)建目錄my-project/ └── docker-compose.yml內(nèi)容services: nginx: image: nginx ports: - 8080:80解釋services服務(wù)列表services:下面每個(gè)就是一個(gè)容器。nginx服務(wù)名字nginx:你自己定義。image使用哪個(gè)鏡像image: nginx等價(jià)docker run nginxports端口ports: - 8080:80等價(jià)-p 8080:804. 啟動(dòng) Compose進(jìn)入目錄cd my-project執(zhí)行docker compose upDocker自動(dòng)創(chuàng)建網(wǎng)絡(luò)拉鏡像創(chuàng)建容器啟動(dòng)服務(wù)后臺(tái)啟動(dòng)docker compose up -d查看docker compose ps類(lèi)似NAME my-project-nginx-1 STATUS running停止docker compose down5. Compose 自動(dòng)創(chuàng)建網(wǎng)絡(luò)以前我們需要docker network create app-netCompose自動(dòng)創(chuàng)建。例如services: mysql: image: mysql backend: image: my-app自動(dòng)network: my-project_default兩個(gè)容器自動(dòng)加入。6. Compose 實(shí)戰(zhàn)MySQL Redis完整例子services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: 123456 ports: - 3306:3306 redis: image: redis ports: - 6379:6379啟動(dòng)docker compose up -d現(xiàn)在兩個(gè)服務(wù)一起運(yùn)行。7. 數(shù)據(jù)卷 Volume Compose生產(chǎn)數(shù)據(jù)庫(kù)必須保存數(shù)據(jù)。修改services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: 123456 volumes: - mysql_data:/var/lib/mysql volumes: mysql_data:重點(diǎn)下面volumes: mysql_data:表示創(chuàng)建 Docker Volume。等價(jià)docker volume create mysql_data8. 環(huán)境變量管理不要直接寫(xiě)密碼MYSQL_ROOT_PASSWORD: 123456生產(chǎn)使用.env例如項(xiàng)目project/ ├── docker-compose.yml └── .env.env:MYSQL_PASSWORD123456compose:environment: MYSQL_ROOT_PASSWORD: ${MYSQL_PASSWORD}啟動(dòng)時(shí)自動(dòng)讀取。9. 完整項(xiàng)目案例現(xiàn)在模擬真實(shí)網(wǎng)站結(jié)構(gòu)shop/ ├── docker-compose.yml ├── backend/ │ └── Dockerfile └── nginx/ └── nginx.conf包含Nginx后端MySQLRedisdocker-compose.ymlservices: nginx: image: nginx ports: - 80:80 depends_on: - backend backend: build: ./backend depends_on: - mysql - redis mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: 123456 volumes: - mysql_data:/var/lib/mysql redis: image: redis volumes: mysql_data:啟動(dòng)docker compose up -d一次啟動(dòng)nginx | backend | mysql redis10. depends_on 是什么例如backend: depends_on: - mysql意思啟動(dòng) backend 前先啟動(dòng) mysql。但是注意它不代表mysql 已經(jīng)完全準(zhǔn)備好。例如MySQL啟動(dòng)需要10秒。backend可能馬上連接失敗。生產(chǎn)需要healthcheck。11. healthcheck生產(chǎn)技巧例如MySQLmysql: image: mysql:8.0 healthcheck: test: [ CMD, mysqladmin, ping ] interval: 10s意思Docker 檢查MySQL 是否真的可用。12. build 自己的鏡像Compose 不只是 image??梢詁ackend: build: context: ./backend意思讀取backend/Dockerfile自動(dòng)構(gòu)建。等價(jià)docker build13. image 和 build 區(qū)別image使用別人已有鏡像image: mysql類(lèi)似docker pull mysqlbuild自己制作build: ./app類(lèi)似docker build .14. 查看日志所有服務(wù)docker compose logs實(shí)時(shí)docker compose logs -f指定docker compose logs nginx15. 重啟服務(wù)全部docker compose restart指定docker compose restart backend16. 進(jìn)入 Compose 容器例如進(jìn)入 backenddocker compose exec backend bash類(lèi)似docker exec -it backend bash17. 更新代碼后的流程開(kāi)發(fā)修改代碼。重新構(gòu)建docker compose build重新啟動(dòng)docker compose up -d18. Compose 文件版本思維以前version: 3現(xiàn)在新版 Docker Compose通常可以省略。推薦services:直接開(kāi)始。19. 企業(yè)真實(shí)部署流程開(kāi)發(fā)代碼 | Dockerfile | 鏡像 | docker-compose.yml服務(wù)器git clone 項(xiàng)目 cd 項(xiàng)目 docker compose up -d整個(gè)系統(tǒng)上線(xiàn)。20. Compose 常用命令總結(jié)功能命令啟動(dòng)docker compose up后臺(tái)啟動(dòng)docker compose up -d停止刪除docker compose down查看狀態(tài)docker compose ps查看日志docker compose logs進(jìn)入容器docker compose exec重新構(gòu)建docker compose build重啟docker compose restart第八章Docker 部署真實(shí)項(xiàng)目從開(kāi)發(fā)到上線(xiàn)前面你已經(jīng)掌握 Docker 的核心技術(shù)鏡像 Image ↓ 容器 Container ↓ 數(shù)據(jù) Volume ↓ 網(wǎng)絡(luò) Network ↓ Dockerfile ↓ Compose現(xiàn)在進(jìn)入真正工作場(chǎng)景一個(gè)項(xiàng)目如何從代碼變成線(xiàn)上運(yùn)行的網(wǎng)站我們模擬一個(gè)真實(shí)互聯(lián)網(wǎng)項(xiàng)目。1. 一個(gè)真實(shí)網(wǎng)站的結(jié)構(gòu)假設(shè)我們開(kāi)發(fā)一個(gè)商城技術(shù)棧前端Vue后端Spring Boot數(shù)據(jù)庫(kù)MySQL緩存Redis入口Nginx最終結(jié)構(gòu)用戶(hù)瀏覽器 | | ↓ Nginx容器 (80/443端口) | ---------------------- | | ↓ ↓ Vue靜態(tài)文件 Spring Boot | ------------------ | ↓ MySQL | ↓ Redis2. 服務(wù)器準(zhǔn)備一般公司服務(wù)器Linux例如Ubuntu 22.04安裝DockerDocker Compose檢查docker version查看docker compose version3. 項(xiàng)目目錄設(shè)計(jì)企業(yè)常見(jiàn)例如shop-system/ ├── docker-compose.yml ├── nginx/ │ └── nginx.conf ├── backend/ │ ├── Dockerfile │ └── app.jar ├── frontend/ │ ├── Dockerfile │ └── dist/ └── mysql/ └── init.sql4. 部署后端 Spring Boot假設(shè)已經(jīng)打包app.jar目錄backend/ ├── Dockerfile └── app.jarDockerfileFROM eclipse-temurin:17-jdk WORKDIR /app COPY app.jar . EXPOSE 8080 CMD [java,-jar,app.jar]解釋FROMJava環(huán)境FROM eclipse-temurin:17-jdk提供JDK17。COPY復(fù)制COPY app.jar .進(jìn)入/app/app.jarCMD啟動(dòng)CMD [java,-jar,app.jar]構(gòu)建docker build -t shop-backend:v1 .測(cè)試docker run \ -p 8080:8080 \ shop-backend:v1訪(fǎng)問(wèn)localhost:80805. 部署 Vue 前端Vue 項(xiàng)目開(kāi)發(fā)npm run build生成dist/里面index.html assets/DockerfileFROM nginx COPY dist/ /usr/share/nginx/html/ EXPOSE 80構(gòu)建docker build \ -t shop-frontend:v1 .運(yùn)行docker run \ -d \ -p 80:80 \ shop-frontend:v1訪(fǎng)問(wèn)http://服務(wù)器IP看到網(wǎng)頁(yè)。6. 為什么需要 Nginx很多新人疑惑Vue 可以直接運(yùn)行為什么還需要 Nginx因?yàn)?Vue 打包后本質(zhì)HTML CSS JS 圖片只是靜態(tài)文件。Nginx 擅長(zhǎng)提供靜態(tài)文件反向代理HTTPS負(fù)載均衡7. Nginx 反向代理后端用戶(hù)訪(fǎng)問(wèn)/api/user希望轉(zhuǎn)給Spring Boot:8080配置nginx.confserver { listen 80; location / { root /usr/share/nginx/html; index index.html; } location /api/ { proxy_pass http://backend:8080; } }重點(diǎn)proxy_pass代理。8. 使用 Compose 管理整個(gè)系統(tǒng)最終docker-compose.ymlservices: nginx: image: nginx ports: - 80:80 volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf depends_on: - backend backend: build: ./backend environment: DB_HOST: mysql REDIS_HOST: redis depends_on: - mysql - redis mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: 123456 volumes: - mysql_data:/var/lib/mysql redis: image: redis volumes: mysql_data:啟動(dòng)docker compose up -d結(jié)果CONTAINER nginx backend mysql redis全部啟動(dòng)。9. 數(shù)據(jù)庫(kù)連接為什么寫(xiě) mysql注意Spring 配置以前spring.datasource.url jdbc:mysql://127.0.0.1:3306/shopDocker錯(cuò)誤。應(yīng)該jdbc:mysql://mysql:3306/shop原因Docker 網(wǎng)絡(luò) DNS。backend 查詢(xún) mysql ↓ Docker DNS ↓ MySQL容器10. 環(huán)境變量管理生產(chǎn)不要寫(xiě)死密碼。錯(cuò)誤MYSQL_ROOT_PASSWORD:123456推薦.env文件MYSQL_PASSWORDxxxxxx MYSQL_DATABASEshopcomposeenvironment: MYSQL_ROOT_PASSWORD:${MYSQL_PASSWORD}11. 自動(dòng)重啟服務(wù)器重啟怎么辦添加restart: always例如backend: restart: always效果服務(wù)器重啟Docker自動(dòng)啟動(dòng)服務(wù)。12. 查看線(xiàn)上日志網(wǎng)站打不開(kāi)第一件事看日志。Nginxdocker compose logs nginx后端docker compose logs backend實(shí)時(shí)docker compose logs -f backend13. 進(jìn)入線(xiàn)上容器排查例如后端docker compose exec backend bash檢查ls環(huán)境env網(wǎng)絡(luò)ping mysql14. 更新版本怎么做比如代碼修改。流程1. 拉代碼git pull2. 重新構(gòu)建docker compose build3. 重啟docker compose up -d完成升級(jí)。15. 零停機(jī)部署進(jìn)階大公司不會(huì)直接停止舊版本 啟動(dòng)新版本因?yàn)闀?huì)中斷。使用藍(lán)綠部署Nginx | ---------------- | | v1容器 v2容器 舊版本 新版本測(cè)試 v2成功切換流量。16. Docker 日志管理默認(rèn)日志存在/var/lib/docker/containers/長(zhǎng)期運(yùn)行會(huì)爆。配置限制大小{ log-driver:json-file, log-opts:{ max-size:10m, max-file:3 } }生產(chǎn)必須做。17. Docker 安全基礎(chǔ)不要直接 root。Dockerfile錯(cuò)誤USER root推薦創(chuàng)建用戶(hù)RUN useradd app USER app不要隨便暴露端口。例如數(shù)據(jù)庫(kù)3306不應(yīng)該開(kāi)放公網(wǎng)。18. Docker 生產(chǎn)檢查清單上線(xiàn)前鏡像? 固定版本不要latest數(shù)據(jù)? Volume數(shù)據(jù)庫(kù)必須持久化。網(wǎng)絡(luò)? 自定義 network密碼? 環(huán)境變量日志? 限制大小重啟? restart安全? 非 root19. 一個(gè)真實(shí)服務(wù)器上線(xiàn)流程公司常見(jiàn)開(kāi)發(fā)電腦 ↓ 提交 Git ↓ CI/CD 自動(dòng)構(gòu)建 ↓ Docker build ↓ 推送鏡像倉(cāng)庫(kù) ↓ 服務(wù)器 pull 鏡像 ↓ docker compose up -d ↓ 上線(xiàn)