Docker入门到实战:从开发到部署,一套环境打通所有流程

Docker就是把你应用和它要的环境打包成一个箱子,到哪都能直接跑。以前最烦的就是“在我机器上好好的啊”,环境不一致简直是噩梦。

第一步:装Docker,我一开始就搞错了

别去看官方文档了,直接上命令:

bash

Ubuntu/Debian

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

CentOS/RHEL

sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum

一套环境打通所有流程"
style="max-width:100%;height:auto;border-radius:8px;box-shadow:0 2px 10px rgba(0,0,0,.08);"
loading="lazy" width="800" height="500">

install docker-ce docker-ce-cli containerd.io

启动并设置开机自启

sudo systemctl start docker
sudo systemctl enable docker

验证安装

docker --version
docker run hello-world
`

装完先把自己加到docker用户组里,不然每次都得敲sudo,烦得很。
`bash
sudo usermod -aG docker $USER
newgrp docker
`

核心概念:镜像、容器、仓库

这三个词,我一开始也绕晕了。后来自己琢磨了个比喻:

  • 镜像:就像炒菜的菜谱,是死的,只读的。
  • 容器:照着菜谱炒出来的一盘菜,是活的,能跑能停。
  • 仓库:就是个存菜谱的网站(Docker Hub),想吃什么去那找。

实战:把个Flask应用塞进Docker

我做了一个巨简单的Web应用,一步步把它打包成镜像。

项目结构就三文件:
`
my-flask-app/
├── app.py # Flask应用
├── requirements.txt # Python依赖
└── Dockerfile # 构建镜像的配方
`

app.py内容:
`python
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
return "Hello from Docker!"

if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
`

requirements.txt:
`
flask==2.3.0
`

最关键的Dockerfile来了。为啥要这么写?因为每个指令都会多一层,层数越少镜像越小,构建越快。

`dockerfile

用轻量级基础镜像(为啥不用ubuntu?太沉了,1.2G变180M的秘密就在这)

FROM python:3.9-slim

设置工作目录,省的复制的时候路径乱套

WORKDIR /app

先复制依赖文件。这是个小技巧,为了利用缓存。只有这个文件变了,才重新下载依赖

COPY requirements.txt .

装依赖

RUN pip install --no-cache-dir -r requirements.txt

最后复制代码,因为代码经常改,放前面缓存就白费了

COPY app.py .

声明一下端口,实际映射还得靠运行时

EXPOSE 5000

启动命令

CMD ["python", "app.py"]
`

构建并运行:
`bash
docker build -t my-flask-app:v1.0 .
docker run -d -p 5000:5000 --name my-app my-flask-app:v1.0
`

去浏览器打开http://localhost:5000,看到那句"Hello from Docker!",就成了。

第二个坑:镜像太大怎么办?

我一开始用python:3.9(带一堆系统工具),镜像1.2G,吓死人。后来换成python:3.9-slim,直接降到180M。如果你还不满意,可以用python:3.9-alpine,能压到50M以下。不过alpine版本有时候兼容性会有点小问题,我一般不推荐。

还有个绝招叫多阶段构建。比如编译型语言(Go、Java),先用个大镜像编译,再换个小的只放编译结果。

`dockerfile

第一阶段:编译

FROM golang:1.20 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp

第二阶段:运行

FROM alpine:3.18
WORKDIR /app
COPY --from=builder /app/myapp .
EXPOSE 8080
CMD ["./myapp"]
`

最后的镜像只有十几兆。一开始觉得这设计反人类,后来发现,是真高效。

(核心示意:一张多阶段构建的流程图,左侧大镜像编译,右侧小镜像运行)

第三个坑:容器之间怎么说话?

实际项目不可能只跑一个容器。比如我有个Web应用要连MySQL,怎么搞?

方法一:用–link(这玩意儿已经废弃了,别用)
方法二:用Docker网络

我推荐方法二,建个自定义网络:
`bash
docker network create my-network

启动MySQL

docker run -d --name mysql-db \
--network my-network \
-e MYSQL_ROOT_PASSWORD=root123 \
-e MYSQL_DATABASE=myapp \
mysql:8.0

启动应用(连到同一个网络)

docker run -d -p 5000:5000 \
--name my-app \
--network my-network \
-e DB_HOST=mysql-db \
my-flask-app:v1.0
`

在app.py里连接数据库时,主机名直接填mysql-db(容器名)就行,Docker会自动帮你解析。

部署实战:用docker-compose一键启动

写个docker-compose.yml文件,世界安静了:

`yaml
version: '3.8'

services:
web:
build: .
ports:
- "5000:5000"
depends_on:
- db
environment:
- DB_HOST=db
- DB_USER=root
- DB_PASSWORD=root123

db:
image: mysql:8.0
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: myapp
volumes:
- mysql-data:/var/lib/mysql

volumes:
mysql-data:
`

启动命令就一行:
`bash
docker-compose up -d
`

从开发到部署,一套配置搞定所有环境。

第四个坑:数据说没就没

容器一删,数据就丢了,这设计真坑爹。其实有方案:卷(Volume)和绑定挂载。

`bash

用卷(推荐,Docker帮你管)

docker run -d -v mysql-data:/var/lib/mysql mysql:8.0

绑定挂载(适合开发时调试,能热加载代码)

docker run -d -v /host/path:/container/path my-app
`

卷的好处是跨容器共享、方便备份、性能好。绑定挂载适合开发时直接改代码看效果。

优化技巧:启动从45秒缩到8秒

镜像大了启动就慢,试试这几个:

  • 搞个.dockerignore文件,把node_modules、.git这些没用的排除掉
  • 合并RUN命令,减少层数:RUN apt-get update && apt-get install -y …,别分两行写
  • –no-cache-dir,省得pip缓存一堆垃圾
  • 基础镜像选最小的(slim或alpine)
  • `dockerignore
    .git
    node_modules
    __pycache__
    *.pyc
    .env
    `

    监控和调试

    常用命令,顺手记一下:
    `bash

    看日志

    docker logs -f my-app

    进容器里看看

    docker exec -it my-app /bin/bash

    看资源占用情况

    docker stats

    清理无用的镜像和容器,释放磁盘空间

    docker system prune -a
    `

    (总结前示意:一张Docker命令速查表,包含构建、运行、网络、卷等关键命令)

    最后说三个能立刻用的点

  • 精简镜像:用slim或alpine基础镜像,配合多阶段构建,从1.2G压到50M以下,真的好用。
  • 网络通信:建个自定义网络,用容器名代替IP,省得端口冲突。
  • 一键部署:用docker-compose管理多容器,从开发到生产就一个up -d
  • 对了,生产环境千万别图省事用root用户跑容器,记得加个USER appuser`限制权限。还有,镜像里别写死密码,用环境变量或者Docker Secrets。

    行了,就这些,开干吧!


    滚动至顶部