概述

本文主要记录了在 Linux 3.10.0-1062.el7.x86_64 下使用 docker-compose 搭建服务的过程,由于公司服务器在内网中,搭建镜像及下载依赖时需要外部代理,如果本机服务无相关限制,可联通外网,配置代理部分忽略即可,其实 firewall 为开启,selinux 为 enforcing 状态。

部署中主要涉及以下内容:

  1. Nginx 代理 MySQL 和 django 服务以及 https 自签名的部署。
  2. 使用 gunicorn 部署 django 服务。
  3. MySQL 相关初始化配置,及建权过程。
  4. 将 .py 文件转为 .pyc 文件

Docker 安装

如果之前安装过的话,需要删除老版本 docker:

sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine

安装构建 docker 所需要的工具;

 sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2

添加 docker 源:

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

安装 docker ce:

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

配置 docker:

sudo systemctl start docker
sudo systemctl enable docker

安装 docker-compose:

# download
sudo curl -L "https://github.com/docker/compose/releases/download/1.25.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# apply exe permissions
sudo chmod +x /usr/local/bin/docker-compose
# add link
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
# check
docker-compose --version

如果在安装中下无法下载相应服务,则表明可能需要配置相应代理或开放相关 ACL 配置,关于相关配置过程可参见Centos7 下代理配置

docker 的代理配置也需要单独做出来,可以参见docker 代理脱坑这篇。

项目结构

下面是 docker-compose 工程构建后完整目录:

├── config
│   ├── auto_start_script.sh
│   ├── mysql
│   │   ├── init
│   │   │   └── init.sql
│   │   ├── my.cnf
│   │   └── my.conf
│   ├── nginx
│   │   ├── conf.d
│   │   │   ├── certs
│   │   │   │   ├── cmi_sdn.crt
│   │   │   │   ├── cmi_sdn.key
│   │   │   │   └── dhparam.pem
│   │   │   ├── ssl.conf
│   │   │   └── ssl.conf.bk
│   │   ├── default.d
│   │   │   └── ssl-redirect.conf
│   │   ├── log
│   │   │   ├── access.log
│   │   │   └── error.log
│   │   └── nginx.conf
│   └── requirements.txt
├── docker-compose.yml
├── Dockerfile
├── db_storage # 创建文件夹就好,用于挂载 mysql 数据
└── project
├── your_project
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── manage.py
└── static
└── frontend

tree -I '*project*|*frontend*|*db_storage*'

  • config 目录:存放 nginx 配置, requirement, mysql 配置
  • docker-compose.yml: 用于编排和管理容器的 yaml 文件
  • Dockerfile: 用于编写 django 镜像的文件
  • project:django 项目代码

Dockerfile 编写

编写 django 的运行环境,如不需要代理可将环境变量删除

FROM python:3.6.8

ENV MY_PROXY_URL="http://173.39.112.117:80"
ENV HTTP_PROXY=$MY_PROXY_URL \
HTTPS_PROXY=$MY_PROXY_URL \
FTP_PROXY=$MY_PROXY_URL \
http_proxy=$MY_PROXY_URL \
https_proxy=$MY_PROXY_URL \
ftp_proxy=$MY_PROXY_URL WORKDIR /src COPY /config/requirements.txt / RUN pip install --no-cache-dir -r /requirements.txt ENV MY_PROXY_URL=
ENV HTTP_PROXY=$MY_PROXY_URL \
HTTPS_PROXY=$MY_PROXY_URL \
FTP_PROXY=$MY_PROXY_URL \
http_proxy=$MY_PROXY_URL \
https_proxy=$MY_PROXY_URL \
ftp_proxy=$MY_PROXY_URL

创建 config/requirements.txt 文件,并添加所需要的 python 依赖包,部署选用 gunicorn. 文件如下:

Django==2.1.7
djangorestframework==3.9.2
djangorestframework-jwt==1.11.0
mysqlclient==1.4.2
PyJWT==1.7.1
requests==2.21.0
gunicorn==19.9.0
django-role-permissions==2.2.1
aiohttp==3.5.4
apscheduler==3.6.3
networkx==2.4
numpy==1.17.4

Nginx 配置

nginx/conf.d/certs 目录下,使用 openssl 进行自签名,生成需要的证书:

sudo openssl req   -x509   -nodes   -days 365   -newkey rsa:2048   -keyout example.key   -out example.crt;

sudo openssl dhparam -out dhparam.pem 2048

编写 nginx 配置文件 config/nginx/conf.d/ssl.conf

upstream web_server {
# ip_hash;
server web:8000 fail_timeout=100s;
#server 10.89.200.40:8000 backup;
keepalive 300;
} upstream topo {
# ip_hash;
server topo:7777 fail_timeout=100s;
#server 10.89.200.40:8000 backup;
keepalive 300;
} server {
listen 443 http2 ssl;
listen [::]:443 http2 ssl; server_name server_IP_address; ssl_certificate /etc/nginx/conf.d/certs/cmi_sdn.crt;
ssl_certificate_key /etc/nginx/conf.d/certs/cmi_sdn.key;
ssl_dhparam /etc/nginx/conf.d/certs/dhparam.pem;
########################################################################
# from https://cipherli.st/ #
# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html #
######################################################################## ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Disable preloading HSTS for now. You can use the commented out header line that includes
# the "preload" directive if you understand the implications.
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff; ##################################
# END https://cipherli.st/ BLOCK #
################################## location / {
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://web_server/;
proxy_connect_timeout 159s;
proxy_send_timeout 600;
proxy_read_timeout 600;
keepalive_timeout 600s;
} listen 8000;
server_name localhost; location /static {
autoindex on;
alias /src/static;
}
} server {
listen 666 http2 ssl;
listen [::]:666 http2 ssl; server_name server_IP_address; ssl_certificate /etc/nginx/conf.d/certs/cmi_sdn.crt;
ssl_certificate_key /etc/nginx/conf.d/certs/cmi_sdn.key;
ssl_dhparam /etc/nginx/conf.d/certs/dhparam.pem;
########################################################################
# from https://cipherli.st/ #
# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html #
######################################################################## ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Disable preloading HSTS for now. You can use the commented out header line that includes
# the "preload" directive if you understand the implications.
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
#add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff; ##################################
# END https://cipherli.st/ BLOCK #
################################## add_header X-Frame-Options sameorigin always; location = / {
root /src/frontend/dist;
index index.html index.htm;
} location ^~ /index.html {
root /src/frontend/dist;
index index.html index.htm; } location ^~ /favicon.png {
root /src/frontend/dist;
} location ^~ /static {
alias /src/frontend/dist/static;
} location ^~ /topo/get_topology/ {
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://topo;
} location ^~ /topo/update_topology/ {
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://topo;
} location ~* /.* {
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://web_server;
proxy_connect_timeout 159s;
proxy_send_timeout 600;
proxy_read_timeout 600;
keepalive_timeout 600s;
} server_name localhost;
}

注意这里的 web 是 docker-compose 编排中的 django 所在容器名称。

topo 是我这里启用的另一服务,忽略即可。

编写 default.d/ssl-redirect.conf 添加 http 到 https 的自动跳转

return 301 https://$host$request_uri/;

编写 config/nginx/nginx.conf 配置入口文件

user  nginx;
worker_processes 1; error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid; events {
worker_connections 1024;
} http {
include /etc/nginx/mime.types;
default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on;
#tcp_nopush on; keepalive_timeout 65; #gzip on; include /etc/nginx/conf.d/*.conf;
} stream {
# log_format main 'mysql - $remote_addr - [$time_local] ';
# access_log /var/log/nginx/access.log main; upstream mysql {
# hash $remote_addr consistent;
server 10.124.207.155:3306;
server 10.124.207.154:3306 backup;
}
server {
listen 3306;#公网机器监听端口
proxy_connect_timeout 10s;
proxy_timeout 800s;
proxy_pass mysql;
}
}

mysql 为 docker-compose 文件下的名称

创建 config/nginx/log/access.log or error.log

MySQL 配置

编写 config/mysql/my.conf

# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock # Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0 log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid #server-id=1
log_bin = mysql-bin # 开启二进制log文件
binlog_format = mixed
#relay-log = relay-bin
#relay-log-index = slave-relay-bin.index
#auto-increment-offset = 1 # 从 1 开始
#auto-increment-increment = 2 # 每次增长 2 character-set-server=utf8 [client]
default-character-set=utf8 [mysql]
default-character-set=utf8 [mysqld]
skip-name-resolve

编写初始化 config/mysql/init/init.sql

CREATE USER 'test'@'%';

GRANT ALL PRIVILEGES ON *.* To 'test'@'%' IDENTIFIED BY 'testPass1!';

FLUSH PRIVILEGES;

CREATE DATABASE IF NOT EXISTS test default charset utf8 COLLATE utf8_general_ci;

编写 docker-compose 文件:

version: '3'

services:
mysql:
image: ctg/mysql:5.7.29
container_name: "mysql"
environment:
MYSQL_ROOT_PASSWORD: "MyNewPass1!"
restart: always
ports:
- "3306:3306"
volumes:
- "/etc/localtime:/etc/localtime:ro"
- "./db_storage:/var/lib/mysql"
- "./config/mysql/my.cnf:/etc/my.cnf"
- "./config/mysql/init:/docker-entrypoint-initdb.d/"
networks:
- app_net proxy_server:
image: ctg/nginx:latest
ports:
- "443:443"
- "3307:3307"
- "444:444"
- "666:666"
volumes:
- "/etc/localtime:/etc/localtime:ro"
- "./project:/src"
- "./config/nginx/conf.d:/etc/nginx/conf.d"
- "./config/nginx/default.d:/etc/nginx/default.d"
- "./config/nginx/log:/var/log/nginx"
- "./config/nginx/nginx.conf:/etc/nginx/nginx.conf"
- "./frontend:/var/frontend"
container_name: "proxy_server"
depends_on:
- web
networks:
- app_net
web:
image: ctg/web:latest
container_name: "ctg_backend"
command: bash -c "python manage.py makemigrations && python manage.py migrate && python manage.py collectstatic --noinput && gunicorn -c gunicorn_config.py ctg.wsgi" ports:
- "8000:8000"
volumes:
- "/etc/localtime:/etc/localtime:ro"
- "./project:/src"
- "/proc:/hostip/:ro"
restart: always
privileged: true
networks:
- app_net topo:
image: ctg/topo:latest
container_name: "ctg_topo"
command: bash -c "python /ctg_topo/manage.py runserver 0.0.0.0:7777" ports:
- "7777:7777"
volumes:
- "/etc/localtime:/etc/localtime:ro"
- "./topo_project/topo_server:/ctg_topo"
restart: always
networks:
- app_net networks:
app_net:
driver: bridge
ipam:
config:
- subnet: 172.26.0.1/16

由于 nginx 和 django 是分开部署的,记得把 django 层收集的静态文件也给 nginx 拷贝一份,否则会导致 admin 管理界面样式丢失。我这里的 frontend 是又另外的 portal 界面,忽略即可

想着修改 django 项目的 settings.py 文件,添加如下内容:

ALLOW_HOSTS = ['web']
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

运行

构建镜像:

docker-compose build

如果上述构建成功的话,就可以运行容器了:

docker-compose up -d

如果 docker-compose 的容器是以守护进程运行的话,可以使用下面的命令查看容器的日志:

docker-compose logs -f web

配置开机自启动

# 配置 docker 自启动
systemctl enable docker

配置docker-compose自启动可参考 自启动. 编写 config/auto_start_script.sh 文件。

将 python 转为 pyc 文件

在 django manage.py 同级别执行

# 生成 pyc 文件:
python -m compileall -b . # 删除 py 文件:
find . -name "*.py" |xargs rm -rf # 删除 pycache 目录:
find . -name "pycache" |xargs rm -rf # 最后将 docker-compose.yml 文件中涉及到的 py 文件 换成 pyc.
需要注意的是 gunicorn_config.py 要备份一份,该文件不要转成 pyc.

如果想要实现通过 Jenkins 自动编译加部署,可以参考Jenkins 实现 CI/CD.

参考

how-to-create-a-self-signed-ssl-certificate-for-nginx-on-centos-7

docker ce install

Nginx 、MySQL、Django 在 Docker-compose 中的部署的更多相关文章

  1. Docker Compose 项目打包部署

    Docker Compose 前面我们使用 Docker 的时候,定义 Dockerfile 文件,然后使用 docker build.docker run 等命令操作容器.然而微服务架构的应用系统一 ...

  2. Docker Compose编排工具部署lnmp实践及理论(详细)

    目录 一.理论概述 编排 部署 Compose原理 二.使用docker compose 部署lnmp 三.测试 四.总结 一.理论概述 Docker Compose是一个定义及运行多个Docker容 ...

  3. Django在生产环境中的部署

    基本思路 1.方案:Nginx+uwsgi 这样大体的流程是:nginx作为服务器最前端,负责接收client的所有请求,统一管理.静态请求由Nginx自己处理.非静态请求通过uwsgi传递给Djan ...

  4. MySQL(6)--复制,docker容器中

    MySQL5.7.11实现replication 启动两个安装好mysql的空的docker image ----------------- shell1  master $docker run -i ...

  5. Nginx+uWSGI+Django+Python在Linux上的部署

    搞了一整天,终于以发现自己访问网络的端口是错误的结束了. 首先要安装Nginx,uWSGI,Django,Python,这些都可以再网上查到. 安装好后可以用 whereis 命令查看是否安装好了各种 ...

  6. 基于Docker Compose构建的MySQL MHA集群

    Docker MySQL MHA 基于Docker 1.13.1之上构建的MySQL MHA Docker Compose Project 可快速启动GTID模式下的MasterHA集群, 主用于My ...

  7. Docker + node(koa) + nginx + mysql 线上环境部署

    在上一篇 Docker + node(koa) + nginx + mysql 开发环境搭建,我们进行了本地开发环境搭建 现在我们就来开始线上环境部署 如果本地环境搭建没有什么问题,那么线上部署的配置 ...

  8. Docker学习笔记之编写 Docker Compose 项目

    0x00 概述 通过阅读之前的小节,相信大家对 Docker 在开发中的应用已经有了一定的了解.作为一款实用的软件,我们必须回归到实践中来,这样才能更好地理解 Docker 的实用逻辑和背后的原理.在 ...

  9. Docker学习笔记之常用的 Docker Compose 配置项

    0x00 概述 与 Dockerfile 一样,编写 Docker Compose 的配置文件是掌握和使用好 Docker Compose 的前提.编写 Docker Compose 配置文件,其本质 ...

  10. Docker学习笔记之使用 Docker Compose 管理容器

    0x00 概述 通过之前的介绍,我们已经基本掌握了构建.运行容器的方法,但这还远远不够,由于 Docker 采用轻量级容器的设计,每个容器一般只运行一个软件,而目前绝大多数应用系统都绝不是一个软件所能 ...

随机推荐

  1. Linux源码安装步骤

    来源:https://www.cnblogs.com/benwu/articles/8436209.html 1. 获取源码 2. 查看INSTALL与README文件    (解压后查看INSTAL ...

  2. 前端开发--ajax

    使用ajax,他是有两个模块的,一个是客户端,一个是服务端. 客户端负责发送数据,发送数据的方式有两种,一种是GET,另一种是POST. 服务端是用来接收,处理数据和发送请求的数据. 要想使用ajax ...

  3. python学习10字典

    '''''''''字典(Dict)是python语言的一个最大的特征1.定义:是可变的无序集合,以键值对为基本元素,可以存储各种数据类型2.表示:{} 列表:[] 元组 () 字符串 ‘’ “” ‘‘ ...

  4. Cent OS 7 添加 EPEL Nux Dextop ELRepo等源

    Cent OS 7 添加第三方yum源 CentOS由于很追求稳定性,所以官方源中自带的软件不多,因而需要一些第三方源. 比如EPEL.ATrpms.ELRepo.Nux Dextop.RepoFor ...

  5. java 8中构建无限的stream

    目录 简介 基本使用 自定义类型 总结 java 8中构建无限的stream 简介 在java中,我们可以将特定的集合转换成为stream,那么在有些情况下,比如测试环境中,我们需要构造一定数量元素的 ...

  6. Spring Boot JPA 中transaction的使用

    文章目录 @Transactional的实现 @Transactional的使用 Transaction的传播级别 REQUIRED SUPPORTS MANDATORY NEVER NOT_SUPP ...

  7. JavaScript Array every()&some()&reduce()方法

    every()方法测试数组的所有元素是否都通过了指定函数的测试. // 每一项都要满足条件才会返回true,只要有一项不满足返回false var arr = [1, 2, 3, 4]; let bl ...

  8. 《例说51单片机(C语言版)(第3版)》——1-3 认识MCS-51的存储器结构

    本节书摘来异步社区<例说51单片机(C语言版)(第3版)>一书中的第1章,第1.3节,作者:张义和,王敏男,许宏昌,余春长,更多章节内容可以访问云栖社区"异步社区"公众 ...

  9. 关于LinearLayout设置权重后width或height不设置0dp的影响说明

    摘要 平时没那么注意LinearLayout布局时权重的问题,设置了权重属性后,通常建议将width或height的属性值设置为0dp,有时候设置权重后,还是习惯将width或height的属性设置为 ...

  10. 跟风微信小程序,生鲜水果店如何借力小程序每天多赚2万块?

    公司旁边的水果店,虽然是一家实体店,但老板有一颗爱玩互联网的心. 老板非常重视线上的营销推广,什么新的线上推广方式都爱尝试一下.公众号大热时做了自己的微信公众号,并且有自己的微信商城,不过线上的销售一 ...