Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

用 docker 一键部署前后端项目 #15

Open
ZhenHe17 opened this issue Sep 24, 2019 · 0 comments
Open

用 docker 一键部署前后端项目 #15

ZhenHe17 opened this issue Sep 24, 2019 · 0 comments

Comments

@ZhenHe17
Copy link
Owner

ZhenHe17 commented Sep 24, 2019

大家都比较反感复杂的环境配置,这里分享一下怎么用 docker 一键配置环境。

先上代码:
示例项目,技术栈:docker nginx egg mysql react

Docker

Docker 属于一种操作系统层面的虚拟化技术。传统虚拟机技术是虚拟出一套硬件,硬件上虚拟操作系统,在该系统上运行应用进程。而 Docker 创建的容器没有自己的内核,而且也没有进行硬件虚拟,极大的简化了容器创建和维护的成本。
Docker 核心概念中有: 镜像(image) 容器(container),它们之间的关系有点像编程中 类 和 实例 的关系,镜像是静态的,可以被提前创建好。容器有着自己的运行状态,允许进入容器,操作容器,容器运行在一个隔离的环境里。
不熟悉 docker 的同学可以先看 Docker — 从入门到实践

Docker Compose

Docker Compose 是 Docker 官方项目,用来定义和运行多个 Docker 容器的应用。通过编写 docker-compose.yml 配置文件,快速的部署分布式应用。文件中通常配置:镜像、端口映射、文件映射、容器间的依赖等。
可以参考 Docker compose 官方文档

部署前端工程

对于前后端分离的项目,部署前端工程通常比较简单。这里把打包好的静态资源用nginx映射好即可。

# ./docker-compose.yml
  nginx:
    build:
      context: ./webapp
    ports: 
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/cert:/etc/nginx/cert
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
    networks:
      - backend
    restart: always

docker-compose.yml 里主要配置了

  • build: -> context: ./webapp 指定镜像通过 ./webapp/Dockerfile 生成
  • ports -> "80:80" 访问本地 localhost 80端口即可访问容器内80端口
  • volumes: -> ./nginx/... 将本地文件映射到容器内,直接修改本地文件就可以修改容器里运行的nginx配置
# ./webapp/Dockerfile
FROM node:12.10.0-alpine as client
RUN mkdir /opt/webapp
WORKDIR /opt/webapp
COPY ./package.json .
RUN npm install --production --registry=https://registry.npm.taobao.org
COPY . .
RUN npm run build

FROM nginx
WORKDIR /usr/app/
COPY --from=client /opt/webapp/build/ /usr/share/nginx/html/

./webapp/Dockerfile 配置分两个阶段:第一个阶段依赖是 node,主要是安装项目依赖 npm install 并打包 npm run build。第二个阶段依赖 nginx,把阶段一打包好的静态资源放进 nginx 目录下。

到这一步为止,前端工程就部署好了,运行 docker-compose up 后可以在 localhost/ 下访问。

部署后端工程

EGG

先把 egg 的工程跑起来

# ./docker-compose.yml
  fe_article_server:
    build:
      context: ./server
    ports:
     - "7001:7001"
    depends_on:
     - db
     - redis
    networks:
     - backend

配置:

  • build: -> context: ./server 指定镜像通过 ./server/Dockerfile 生成
  • ports -> "7001:7001" 本地端口映射,这个无关紧要,后面会通过 nginx 代理它
  • depends_on: -> 它依赖 db和redis 这两个服务。稍后会展开 mysql 和 redis 的配置
# ./webapp/Dockerfile
FROM node:12.10.0-alpine
RUN apk --update --no-cache add tzdata bash curl \
    && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && echo "Asia/Shanghai" > /etc/timezone \
    && apk del tzdata
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY ./package.json /usr/src/app/
RUN npm install --production --registry=https://registry.npm.taobao.org
COPY . /usr/src/app
COPY wait-for-it.sh /
CMD /wait-for-it.sh db:3306 -- npm run start

这里和 webapp 相似,RUN apk ... 设置了上海时区、npm install 安装项目依赖、npm run start 启动项目,egg 默认运行在 7001 端口。

MySQL

我们直接使用官方镜像,只需要配置 docker-compose.yml 不需要 Dockerfile

# ./docker-compose.yml
  db:
    image: mysql:5.7
    ports:
      - 3306:3306
    environment:
      - MYSQL_DATABASE=article
      - MYSQL_USER=worker
      - MYSQL_PASSWORD=wptworker
      - MYSQL_ROOT_PASSWORD=wptroot
      - TZ=UTC
    volumes:
      - ./db/conf.d:/etc/mysql/conf.d:ro
      - ./db/logs:/var/log/mysql:rw
      - ./db/initdb.d:/docker-entrypoint-initdb.d:ro
    networks:
     - backend

主要配置了 mysql 的默认数据库、账号密码、配置文件映射。 docker-compose up 后数据库直接启动在3306端口,可以用命令行或者图形化工具连接管理数据库

Redis

redis 和 mysql 大体相同

# ./docker-compose.yml
  redis:
    build: ./redis
    ports:
      - "6379:6379"
    volumes:
      - ./redis/redis.conf/:/usr/local/etc/redis.conf
      - ./redis/data:/usr/local/redis/data
      - ./redis/redis.log:/usr/local/redis/redis.log
    restart: always
    container_name: redis
    networks:
      - backend
# ./redis/Dockerfile
FROM redis
CMD [ "redis-server", "/usr/local/etc/redis.conf" ]

在 Dockerfile 中使用了官方镜像,加了一行配置指定了 redis.conf 的位置,这个路径已经在 yml 文件中映射好了。

踩坑

Dockerfile

COPY ./package.json .
RUN npm install --production --registry=https://registry.npm.taobao.org
COPY . .
RUN npm run build

这里我们 COPY 了两次。

COPY . .
RUN npm install --production --registry=https://registry.npm.taobao.org
RUN npm run build

COPY 一次虽然可以,但是 docker 构建镜像时,是会分层缓存的。一旦目录下有任何修改,这三条指令就会重新执行,之前的缓存会无效。
而先 COPY ./package.json . 则不同,只要项目依赖不变,再次构建时,npm install 就会使用之前的缓存,大家应该知道,安装依赖这一步是比较慢的。

node-sass

如果安装 node-sass 出了问题,可以直接用镜像 blairguk/node-sass-alpine:8.11.0 代替 node:10-alpine 镜像。

容器内访问宿主机的 localhost

nginx代理很可能需要代理本机上的其他端口。虽然你可以直接读本机 IP 来访问宿主机,但是这就和当前环境绑定了。这很不 docker ,笔者在这里用 qoomon/docker-host 镜像,配置好 networks 以后,访问 dockerhost(或者你起的服务名) 即可访问宿主机 localhost。附上配置:

# ./docker-compose.yml
  dockerhost:
      image: qoomon/docker-host
      cap_add: [ 'NET_ADMIN', 'NET_RAW' ]
      restart: on-failure
      networks:
      - dev

总结

在我们使用 docker 之前,在新环境部署项目通常都比较繁杂比较痛苦。mysql、nginx、redis、前后端项目挨个安装挨个配置。而现在只需要 docker-compose up 🚀🚀🚀只能说爽的一比了。
当然 docker 除了部署便利,在分布式和虚拟机技术上也有着极大的价值,有兴趣的同学好好学呀 ^ ^

参考文章

Docker — 从入门到实践
Docker官方文档

@ZhenHe17 ZhenHe17 changed the title 用 docker 一键部署你的前后端项目 用 docker 一键部署前后端项目 Sep 25, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant