使用minikube在本机搭建kubernetes集群

Kubernetes(k8s)是自动化容器操作的开源平台,基于这个平台,你可以进行容器部署,资源调度和集群扩容等操作。如果你曾经用过Docker部署容器,那么可以将Docker看成Kubernetes底层使用的组件,Kubernetes是Docker的上层封装,通过它可以很方便的进行Docker集群的管理。今天我们使用minikube在单机上进行Kubernetes集群的部署,目的是让我们对k8s有个初步的认识。

安装docker

首先安装docker环境,不详细说明了,网上资料一大堆,可以参考官方安装文档

Mac: https://docs.docker.com/docker-for-mac/install/

Ubuntu: https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/

CentOS: https://docs.docker.com/engine/installation/linux/docker-ce/centos/

当然,如果上面所有方法你都失败了,也可以尝试直接下载binary可执行文件,然后启动docker即可 https://docs.docker.com/engine/installation/linux/docker-ce/binaries/

安装Minikube

Mac

# 如未安装cask,自行搜索 brew安装cask
brew cask install minikube

minikube -h

Linux

# 下载v0.24.1版本
curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.24.1/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/

# 也可以下载最新版,但可能和本文执行环境不一致,会有坑
curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/

minikube -h

安装Kubectl

kubectl即kubernetes的客户端,通过他可以进行类似docker run等容器管理操作

curl -Lo kubectl https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/

kubectl -h

启动程序

启动minikube

sudo minikube start

首次启动会下载localkube,下载过程可能会失败,会有如下提示,重试几次即可

Starting local Kubernetes v1.8.0 cluster...
Starting VM...
Downloading Minikube ISO
 64.70 MB / 140.01 MB [====================>-----------------------]  46.21% 14s
E0105 14:06:03.884826   10434 start.go:150] Error starting host: Error attempting to cache minikube ISO from URL: Error downloading Minikube ISO: failed to download: failed to download to temp file: failed to copy contents: read tcp 10.0.2.15:47048->172.217.24.16:443: read: connection reset by peer.

================================================================================
An error has occurred. Would you like to opt in to sending anonymized crash
information to minikube to help prevent future errors?
To opt out of these messages, run the command:
    minikube config set WantReportErrorPrompt false
================================================================================
Please enter your response [Y/n]:

如果下载成功,但是报了诸如VBoxManage not found这样的错误,如下

Starting local Kubernetes v1.8.0 cluster...
Starting VM...
Downloading Minikube ISO
 140.01 MB / 140.01 MB [============================================] 100.00% 0s
E0105 14:10:00.035369   10474 start.go:150] Error starting host: Error creating host: Error executing step: Running precreate checks.
: VBoxManage not found. Make sure VirtualBox is installed and VBoxManage is in the path.

 Retrying.
E0105 14:10:00.035780   10474 start.go:156] Error starting host:  Error creating host: Error executing step: Running precreate checks.
: VBoxManage not found. Make sure VirtualBox is installed and VBoxManage is in the path
================================================================================
An error has occurred. Would you like to opt in to sending anonymized crash
information to minikube to help prevent future errors?
To opt out of these messages, run the command:
    minikube config set WantReportErrorPrompt false
================================================================================
Please enter your response [Y/n]:

解决办法是安装 VirtualBox【对于windows或者mac】 再重新启动;当然如果你是Linux,也可以执行如下命令启动minikube,此时就不需要安装VirtualBox了。

因为minikube默认需要虚拟机来初始化kunernetes环境,但Linux是个例外,可以追加–vm-driver=none参数来使用自己的环境,说明见https://github.com/kubernetes/minikube#quickstart

# linux 下独有,不依赖虚拟机启动
sudo minikube start --vm-driver=none

# 如果是Mac or Windows,安装VirtualBox后再重新start即可
sudo minikube start

如果安装了虚拟机,或者使用了–vm-driver=none参数,并且下载完毕,会有如下提示运行成功

Starting local Kubernetes v1.8.0 cluster...
Starting VM...
Getting VM IP address...
Moving files into cluster...
Downloading localkube binary
 148.25 MB / 148.25 MB [============================================] 100.00% 0s
 0 B / 65 B [----------------------------------------------------------]   0.00%
 65 B / 65 B [======================================================] 100.00% 0sSetting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.
===================
WARNING: IT IS RECOMMENDED NOT TO RUN THE NONE DRIVER ON PERSONAL WORKSTATIONS
    The 'none' driver will run an insecure kubernetes apiserver as root that may leave the host vulnerable to CSRF attacks

When using the none driver, the kubectl config and credentials generated will be root owned and will appear in the root home directory.
You will need to move the files to the appropriate location and then set the correct permissions.  An example of this is below:

    sudo mv /root/.kube $HOME/.kube # this will write over any previous configuration
    sudo chown -R $USER $HOME/.kube
    sudo chgrp -R $USER $HOME/.kube

    sudo mv /root/.minikube $HOME/.minikube # this will write over any previous configuration
    sudo chown -R $USER $HOME/.minikube
    sudo chgrp -R $USER $HOME/.minikube

This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true
Loading cached images from config file.

启动一个容器服务

# kube-nginx999 是要定义的容器名称 nginx:latest表明要用nginx镜像 --port=80表明容器对外暴露80端口
sudo kubectl run kube-nginx999 --image=nginx:latest --port=80

> deployment "kube-nginx999" created

查看状态

sudo kubectl get pods

NAME                             READY     STATUS              RESTARTS   AGE
nginx999-55f47cb99-46nm8         1/1       containerCreating   0          38s

稍等一分钟左右,如果你的服务一直是containerCreating状态,没有变化,那就是创建实例出现问题,如下方法查看log

sudo minikube logs

日志中出现 failed pulling image… 则是因为镜像拉取失败导致服务创建失败,原因?GFW嘛!服务在拉取自身需要的gcr.io/google_containers/pause-amd64:3.0镜像时失败了,如下报错。

Jan 05 03:52:58 minikube localkube[3624]: E0105 03:52:58.952990    3624 kuberuntime_manager.go:632] createPodSandbox for pod "nginx666-864b85987c-kvdpb_default(b0cc687d-f1cb-11e7-ba05-080027e170dd)" failed: rpc error: code = Unknown desc = failed pulling image "gcr.io/google_containers/pause-amd64:3.0": Error response from daemon: Get https://gcr.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)

解决方法:用本地镜像替代

原理就是使用阿里云的镜像下载到本地,然后命名为minikube使用的gcr.io的同名镜像,替代远端镜像即可

# 下载阿里云镜像
docker pull registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0

# 本地命名为 gcr.io/google_containers/pause-amd64:3.0
docker tag registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0 gcr.io/google_containers/pause-amd64:3.0

重新启动服务

增加 –image-pull-policy=IfNotPresent 参数,表明优先使用本地镜像,不从远端拉取

sudo kubectl run kube-nginx999 --image=nginx:latest --port=80 --image-pull-policy=IfNotPresent

如果提示已经存在,换个名字重新执行即可。这时候查看服务状态应该是如下Running状态代表创建成功,但此时还不能访问容器

sudo kubectl get pods

NAMESPACE     NAME                             READY     STATUS             RESTARTS   AGE
default       kube-nginx999-77867567f5-48czx   1/1       Running            2          16h

发布服务

sudo kubectl expose deployment kube-nginx999 --type=NodePort

> service "kube-nginx999" exposed

查看服务地址

sudo minikube service kube-nginx999 --url

> http://127.0.0.1:30690

上面命令展示的地址即启动的nginx容器服务地址,访问 http://127.0.0.1:30690 即可出现nginx首页,服务成功启动!

PS: 访问http://localhost:30690是不可以的。

dashboard 管理后台

dashboard是kubernetes提供的容器服务管理后台,可视化界面,用来进行机器负载,集群管理,镜像扩容,配置数据等相关操作

启动dashboard

# 会打印出管理后台地址
sudo minikube dashboard --url

# 或者用下面写法,会自动打开默认浏览器,但我的一直失败,没有打开默认浏览器,没关系,执行后自己打开也行
sudo minikube dashboard

但初次会报下面的两种错误之一

# 1
Could not find finalized endpoint being pointed to by kubernetes-dashboard: Error validating service: Error getting service kubernetes-dashboard: services "kubernetes-dashboard" not found

# 2
Waiting, endpoint for service is not ready yet...
Waiting, endpoint for service is not ready yet...

如果查看log的话,会找到和pause一样的错误,即在镜像拉取的时候失败,解决方法如下,将所有kubernetes需要的镜像全部用阿里源下载到本地,然后命名为gcr.io…,来让minikube不从远端下载

如果不确定应该将tag重命名为什么的话,可以执行sudo grep ‘image:’ -R /etc/kubernetes看到默认情况下需要的镜像名以及版本号,对应去 https://dev.aliyun.com/search.html 搜索下载,然后命名为上面配置中定义的tag即可,当然,你可以在阿里云下载1.1然后重命名为1.2也没关系,差几个小版本不会有太大影响。

docker pull registry.cn-hangzhou.aliyuncs.com/google-containers/kubernetes-dashboard-amd64:v1.7.1
docker tag registry.cn-hangzhou.aliyuncs.com/google-containers/kubernetes-dashboard-amd64:v1.7.1 gcr.io/google_containers/kubernetes-dashboard-amd64:v1.8.0

docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-addon-manager:v6.4-beta.2
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/kube-addon-manager:v6.4-beta.2 gcr.io/google-containers/kube-addon-manager:v6.4-beta.2

docker pull registry.cn-shenzhen.aliyuncs.com/gcrio/k8s-dns-kube-dns-amd64:latest
docker tag registry.cn-shenzhen.aliyuncs.com/gcrio/k8s-dns-kube-dns-amd64:latest gcr.io/google_containers/k8s-dns-kube-dns-amd64:1.14.5

docker pull registry.cn-hangzhou.aliyuncs.com/google-containers/k8s-dns-dnsmasq-nanny-amd64:1.14.5
docker tag registry.cn-hangzhou.aliyuncs.com/google-containers/k8s-dns-dnsmasq-nanny-amd64:1.14.5 gcr.io/google_containers/k8s-dns-dnsmasq-nanny-amd64:1.14.5

docker pull registry.cn-hangzhou.aliyuncs.com/google-containers/k8s-dns-sidecar-amd64:1.14.5
docker tag registry.cn-hangzhou.aliyuncs.com/google-containers/k8s-dns-sidecar-amd64:1.14.5 gcr.io/google_containers/k8s-dns-sidecar-amd64:1.14.5

docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/storage-provisioner:v1.8.1
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/storage-provisioner:v1.8.1 gcr.io/k8s-minikube/storage-provisioner:v1.8.1

然后重启minikube

sudo minikube stop
sudo minikube start [--vm-driver=none] # linux没装virtualbox的情况下需要加上后面的参数

再次执行

sudo minikube dashboard --url

> http://127.0.0.1:30000/

访问 http://127.0.0.1:30000/ 即可看到操作后台

未分类

写在最后

如果你下载工具时提示下载错误,基本上就是因为GFW,所以如果你有本地ss能够科学上网的话,可以在终端里执行下面命令,让 curl wget等命令也会走代理,加快下载

export http_proxy='socks5:127.0.0.1:1080'

有个坑,执行完以后访问 127.0.0.1 也是会走代理,这时候当然要换一个tab访问即可。

使用Jenkins部署应用到Kubernetes

【编者的话】这篇文章基于去年5月进行的一次Kubernetes使用情况调查,阐述了使用Jenkins作为持续集成工具部署应用程序到Kubernetes的现状,对于大家如何进行CI/CD工具的选型有参考意义。

新的技术栈正不断交付Kubernetes开源容器编排引擎的内容。 本周我们将报告如何将应用程序实际部署到Kubernetes。 当在容器编排、持续交付流水线或配置管理工具之间进行选择时,我们2017年5月进行的Kubernetes调查的受访者经常表示他们使用编排框架来部署应用程序。 虽然有些人曾经把Kubernetes想象成可以做任何事情的瑞士军刀,但实际上他们对应用程序部署中的Kubernetes的角色有着更细致的了解。

当更直接地问到他们是否使用Jenkins将应用程序部署到Kubernetes时,45%的人表示赞成,另有36%的Kubernetes用户使用其它的持续部署(CD)流水线将应用程序部署到Kubernetes,其中GitLab CI和CircleCI是被提及最多的。请注意,调查问题的性质意味着这些信息不能用来决定市场份额,其他工具的整体采用率可能高于下图所示。

未分类

这就是说,Jenkins仍然是最常用的持续集成(CI)工具。 未来的研究将不会问是否使用Jenkins,而是会问在组织流水线中的核心地位。 在许多情况下,同一公司内的不同团队将使用竞争产品。 在其他情况下,Jenkins是更大工作流程中的一个小组件,另一个供应商的工具会是CD流水线图中的焦点。

深入挖掘一下,我们发现小公司(两到一百名员工)相对于平均情况使用Jenkins的可能性较小(38%比45%),可能是因为他们以前没有需要部署工作流的大型组织。 这与我们上周写到的一个趋势是一致的,即不同规模的团队倾向于使用不同的CI/CD工具。

受访者认为,应用程序的自动化部署是使用成熟的Kubernetes一个关键优势。 许多受访者描述了交付流水线如何与Kubernetes所带来的更大的组织变革相关联。 有人说:“在我们的早期阶段,改进开发人员的工作流程,使开发人员能够思考他们的代码是如何在生产环境中运行的,这是我们想要用Kubernetes实现的最重要的事情。”

我们知道有65%的生产环境用户在Kubernetes上运行应用程序开发工具。 在这方面,Kubernetes对于持续部署和提供“基础设施即代码”至关重要。

iptables查看、开放、删除端口、保存设置

iptables选项

-t<表>:指定要操纵的表;
-A:向规则链中添加条目;
-D:从规则链中删除条目;
-i:向规则链中插入条目;
-R:替换规则链中的条目;
-L:显示规则链中已有的条目;
-F:清楚规则链中已有的条目;
-Z:清空规则链中的数据包计算器和字节计数器;
-N:创建新的用户自定义规则链;
-P:定义规则链中的默认目标;
-h:显示帮助信息;
-p:指定要匹配的数据包协议类型;
-s:指定要匹配的数据包源ip地址;
-j<目标>:指定要跳转的目标;
-i<网络接口>:指定数据包进入本机的网络接口;
-o<网络接口>:指定数据包要离开本机所使用的网络接口。

查看防火墙规则

# iptables -L -n -v

增加防火墙规则:开放指定的端口

iptables -A INPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT               #允许本地回环接口(即运行本机访问本机)
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT    #允许已建立的或相关连的通行
iptables -A OUTPUT -j ACCEPT         #允许所有本机向外的访问
iptables -A INPUT -p tcp --dport 22 -j ACCEPT    #允许访问22端口
iptables -A INPUT -p tcp --dport 80 -j ACCEPT    #允许访问80端口
iptables -A INPUT -p tcp --dport 21 -j ACCEPT    #允许ftp服务的21端口
iptables -A INPUT -p tcp --dport 20 -j ACCEPT    #允许FTP服务的20端口
iptables -A INPUT -j reject       #禁止其他未允许的规则访问
iptables -A FORWARD -j REJECT     #禁止其他未允许的规则访问

删除已添加的iptables规则

将所有iptables以序号标记显示,执行:
# iptables -L -n --line-numbers

比如要删除INPUT里序号为2的规则,执行:
# iptables -D INPUT 2

屏避IP

# iptables -I INPUT -s 123.45.6.7 -j DROP       #屏蔽单个IP的命令
# iptables -I INPUT -s 123.0.0.0/8 -j DROP      #封整个段即从123.0.0.1到123.255.255.254的命令
# iptables -I INPUT -s 124.45.0.0/16 -j DROP    #封IP段即从123.45.0.1到123.45.255.254的命令
# iptables -I INPUT -s 123.45.6.0/24 -j DROP    #封IP段即从123.45.6.1到123.45.6.254的命令是

保存iptables更改

最后一部最重要,iptables规则全部输入完成后,都要进行一次保存,否则重启后还是原来的规则。

/etc/rc.d/init.d/iptables save

但是现在Kali版本的Linux不知道怎么保存。

IPTABLES 和 FIREWALLD 防火墙简单使用介绍

未分类

iptables命令是Linux上常用的防火墙软件,是netfilter项目的一部分。可以直接配置,也可以通过许多前端和图形界面配置。

安装IPTable IPTable-service

使用root用户登录,运行以下命令:

#先检查是否安装了iptables
service iptables status
#安装iptables
yum install -y iptables

#升级iptables
yum update iptables

#安装iptables-services
yum install iptables-services

开启IPTables服务

使用root用户登录,运行以下命令:

#开机自启动iptables服务
systemctl enable iptables.service
#启动服务
systemctl start iptables.service

#重启服务
systemctl restart iptables.service

#查看状态
systemctl status iptables.service

禁用/停止自带的firewalld服务

使用root用户登录,运行以下命令:

#停止firewalld服务
systemctl stop firewalld
#禁用firewalld服务
systemctl mask firewalld

设置IPTables现有规则

使用root用户登录,运行以下命令:

#查看iptables现有规则
iptables -L -n
#先允许所有,不然有可能会杯具
iptables -P INPUT ACCEPT

#清空所有默认规则
iptables -F

#清空所有自定义规则
iptables -X

开放端口

使用root用户登录,运行以下命令:

#开放22端口
iptables -A INPUT -p tcp –dport 22 -j ACCEPT

保存规则设定

使用root用户登录,运行以下命令:

#保存上述规则
service iptables save

centos 7版本以后默认使用firewalld,所以使用firewalld是趋势,要及时跟上脚步。

开启firewalld服务

使用root用户登录,运行以下命令:

#启动
systemctl start firewalld
#查看状态
systemctl status firewalld 或者 firewall-cmd –state

#停止
systemctl disable firewalld

#禁用
systemctl stop firewalld

开放、禁用端口

使用root用户登录,运行以下命令:

#开放端口
firewall-cmd –zone=public –add-port=8080/tcp –permanent

#禁用端口
firewall-cmd –zone=public –remove-port=80/tcp –permanent

设置firewalld

使用root用户登录,运行以下命令:

#查看所有打开的端口
firewall-cmd –zone=public –list-all

#更新防火墙规则
firewall-cmd –reload

docker 升级到最新版

步骤

1、卸载旧版 docker

> rpm -qa | grep docker # 也可以使用 yum list installed | grep docker 
docker-engine-1.13.0-1.el7.centos.x86_64
docker-engine-selinux-1.13.0-1.el7.centos.noarch
> yum remove docker-engine-1.13.0-1.el7.centos.x86_64
> yum remove docker-engine-selinux-1.13.0-1.el7.centos.noarch

2、升级至最新版

> curl -fsSL https://get.docker.com/ | sh

3、重启docker

> systemctl restart docker # centos 7
> service docker restart # centos 6

4、查看升级后的版本

> docker version # docker -v

【Docker】如何修复无法启动的容器

先说说这个问题的起因:

Docker容器后台运行,就必须有一个前台进程!

OK,有次手贱,把容器内的php-fpm配置文件中的daemon改为yes,导致了没有前台进程,因此,容器启动后就停止了。
那么问题变成,如何修改没有启动的容器内的文件?(PS:正常情况下可以通过 docker exec命令打开容器的一个shell终端进去修改)

解决方案:创建新镜像

把这个问题容器用docker commit提交到一个新的镜像,然后用docker run -it 基于新镜像运行一个新的容器进去改变(修复)配置文件。
再通过新的容器再提交一个新的镜像,然后在基于新的镜像重新启动容器(同最初的容器)。
这个方法是可行的,但问题是步骤多,而且提交了新的镜像,对于后续维护增加了复杂性。

#把要修复的容器提交为镜像
docker commit <container_id> <image_name>:<tag>
docker rm <container_id> #这个删除老的容器,反正也用不了
#查看刚建立的新镜像
REPOSITORY                               TAG                 IMAGE ID            CREATED             SIZE
zhibin/php5                              2018                c6532c5ece91        10 minutes ago      1.549 GB
#利用这个新镜像创建容器,进入容器,修复配置文件
docker run -it --name tmp-fixphp5 zhibin/php5:2018 /bin/bash
#重新提交镜像
docker commit <container_id> <image_name>:<tag>
#创建修复后的容器
docker run -d --volumes-from nginx_server --name php-fpm_server_2018 --dns=10.100.17.21 --cap-add SYS_PTRACE -p 9000:9000 zhibin/php5:201802

Shell 实现 docker 的健康检查及服务重启功能

最近配置一台 CentOS 7.1 的服务器, 安装了 docker-ce 版本为: Docker version 17.09.1-ce, 启用 docker swarm, 创建 stack 时,发现如下错误:

start container failed: subnet sandbox join failed for "10.255.0.0/16": overlay subnet 10.255.0.0/16 failed check with host route table: requested network overlaps with existing network

具体错误如图:

未分类

原因可能是上层网络占用了 10.255.0.0/16 的部分网段导致。 所以只有放弃 swarm 模式,由于应用比较简单,所以只需使用 docker-compose 就够啦, 只是docker 自带的健康检查失去了意义,只是标识是否健康,没有进程监控健康的状态及恢复服务的操作。
最后决定使用 SHELL 实现这一功能。

先写好自己的docker-compose.yml, 比如PHP+NGINX+REDIS的服务,具体如下:

version: '3.3'
services:
  redis:
    image: redis:3
    restart: always
    volumes:
      - /xmisp/redis/conf:/usr/local/etc/redis
      - /xmisp/redis/data:/var/lib/redis
      - /xmisp/redis/log:/var/log/redis
    ports:
      - 10.0.21.30:6379:6379/tcp
    command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
  php:
    image: davinbao/php-fpm:latest
    restart: always
    volumes:
      - /xmisp/php/conf/www.conf:/usr/local/etc/php-fpm.d/www.conf:ro
      - /xmisp/php/log:/var/log/php-fpm
      - /xmisp/www:/home/www
    ports:
      - 10.0.21.30:9000:9000/tcp
  nginx:
    image: davinbao/nginx:latest
    restart: always
    volumes:
      - /xmisp/nginx/conf:/etc/nginx/conf.d
      - /xmisp/nginx/log:/var/log/nginx
      - /xmisp/www:/home/www
    ports:
      - 80:80/tcp

SHELL 实现健康检查及重启服务, 具体如下:

#!/bin/bash

ADDRESS=$1
COMPOSE_FILE=$2
STATE=0


while true ;do

    HTTP_CODE=`curl -I -m 10 -o /dev/null -s -w %{http_code}"n" ${ADDRESS}`
    if [ "${HTTP_CODE}" != 200 ];then
        let STATE=STATE+1
        echo `date +"%Y-%m-%d %H:%M:%S"` The ${STATE} time can not access
    else
        echo `date +"%Y-%m-%d %H:%M:%S"` Success
        break
    fi

    if [ $STATE -gt 2 ];then
        echo Can not access ${ADDRESS} ,service will reboot!
        docker-compose -f ${COMPOSE_FILE} down
        docker-compose -f ${COMPOSE_FILE} up -d
        break
    fi
    sleep 15

最后配置 crontab 每两分钟执行该脚本:

> crontab -e

*/2 * * * * /xmisp/www/redirect-system/health_check.sh http://localhost /xmisp/www/redirect-system/docker-compose.yml >> /xmisp/www/redirect-system/storage/logs/health_check.log

脚本的功能是每两分钟检查一次80端口,如果不通,将重启整个服务。

使用 Nginx 和 Gunicorn 部署 Django 博客

我们博客的基础功能已经开发的基本差不多了,虽然还有很多地方可以完善,但我们还是希望早点把博客部署到服务器上,让他人可以通过外网访问。至于有待完善的地方,可以等部署完后一点点地迭代和改进。现在就让我们来把博客部署到服务器上吧!

注意:本文的每一个步骤都在真实环境下验证无误。除非你知道自己在做什么,否则我们建议每一步均严格按照教程的指导来,这样能保证你顺利完成部署。

部署前准备

我们将使用比较流行的 Nginx + Gunicorn 的方式将 Django 开发的博客部署到自己的服务器,让别人能够通过域名访问你的博客。至于 Nginx、Gunicorn 是什么暂时放到一边,读完本教程后你就会知道它们的作用和使用方法了。
为了部署我们的博客,需要满足以下两个条件:

  1. 有一台可以通过外网访问的服务器。
  2. 有一个域名。

如果你已经满足以上条件,可以直接跳到后面的搭建服务器部分。这里简单介绍一下我目前所知的以最低成本满足以上两个条件的方式。

购买服务器

如果你是学生,推荐购买阿里云服务器,学生优惠价是 9.9 元/月,而且服务器性能比较高。购买地址:阿里云服务器学生专区。具体的购买步骤这里就不赘述了,根据网站的指引相信你肯定能够购买成功。只是注意一点的是在选服务器类型的时候选择公共镜像,这样系统比较纯净。操作系统建议选 ubuntu 14.04 64位,这是本教程使用的服务器环境。

如果你不是学生,推荐购买搬瓦工 vps。目前最便宜的是 19.9美元/年,缺点是服务器性能没有阿里云高,但优点是顺带可以用它来搭梯子,从此访问 google、youtube 不是梦(基于 shadowsocks 只需简单几步就可以搭建起自己的梯子服务器)。同样购买的过程就不赘述了,搬瓦工 vps 中文网 有超级详细的指引。只是注意安装操作系统时建议选 ubuntu 14.04 64位,这是本教程使用的服务器环境。

如果你不差那点钱,随意选择一个云服务器提供商购买一个云服务器即可。

购买域名

域名服务商很多,我这里使用的是 阿里云域名注册系统。域名是网站的门牌,如果打算长期运营这个网站建议多考虑考虑,选一个适当的域名。如果只是为了测试,随便注册一个域名即可,一些非常见后缀的域名非常便宜,一般 10元/年就能搞定。但注意一点根据工信部规定,以下后缀的域名需要实名认证后才能使用:

.cn/.com/.net/.top/.xyz/.vip/.club/.ren/.wang/.shop/.xin/.中国/.信息/.公司/.网络/.广东/.佛山

如果你购买的是上述后缀的域名,意味着需要提交个人的身份资料实名认证后才能正常使用,这通常需要花费几天的时间。所以如果只为了测试和学习部署的话,最好避开上述后缀的域名。

搭建服务器

本教程使用的本地环境为 Windows 10,服务器环境为 ubuntu 14.04(64 位)。如果你的环境和我的有所差异导致一些命令无法执行,将这些命令转换为你所在环境的命令执行即可。

远程登录到服务器

服务器通常位于云端,需要使用远程登录工具登录后才能对服务器进行操作。我使用的是 Xshell,Windows 下百度 Xshell 下载安装即可,软件对学校和个人用户是免费的。
如何远程登录到服务器这里就不赘述了,相信你参考网上的一些教程肯定能够顺利登录。假如你和我一样使用 Xshell 的话,这里有一篇很详细的教程可以参考:教你怎么使用xshell远程连接linux服务器。

安装软件

顺利连接到远程服务器了。如果是一台全新服务器的话,通常我们是以 root 用户登录的。在 root 下部署代码不安全,最好是建一个新用户(如果你已经以非 root 用户登录的话可以跳过这一步)。下面的一些列命令将创建一个拥有超级权限的新用户:

# 在 root 用户下运行这条命令创建一个新用户,yangxg 是用户名
# 因为我叫杨学光,所以我取的用户名是 yangxg
# 选择一个你喜欢的用户名,不一定非得和我的相同
root@localhost:~# useradd -m -s /bin/bash yangxg

# 把新创建的用户加入超级权限组
root@localhost:~# usermod -a -G sudo yangxg

# 为新用户设置密码
# 注意在输密码的时候不会有字符显示,不要以为键盘坏了,正常输入即可
root@localhost:~# passwd yangxg

# 切换到创建的新用户
root@localhost:~# su - yangxg

# 切换成功,@符号前面已经是新用户名而不是 root 了
yangxg@localhost:~$

新用户创建并切换成功了。如果是新服务器的话,最好先更新一下系统,避免因为版本太旧而给后面安装软件带来麻烦。运行下面的两条命令:

yangxg@localhost:~$ sudo apt-get update
yangxg@localhost:~$ sudo apt-get upgrade

接下来就可以安装必要的软件了,这里我们需要用到的软件有 Nginx、Pytohn3、Git、pip 和 virtualenv。

yangxg@localhost:~$ sudo apt-get install nginx
yangxg@localhost:~$ sudo apt-get install git python3 python3-pip
yangxg@localhost:~$ sudo pip3 install virtualenv

解析域名到服务器的 IP 地址

将域名和服务器的 IP 地址绑定后,用户就可以通过在浏览器输入域名来访问服务器了。

各大域名服务商都提供了域名解析服务,但其配置界面各有差异,请依据其指引完成域名解析。下面是我使用的阿里云域名解析页面。

未分类

启动 Nginx 服务

Nginx 是用来处理静态文件请求的。比如当我们访问一个博客文章详情页面时,服务器会接收到下面两种请求:

  • 显示文章的详情信息,这些信息通常保存在数据库里,因此需要调用数据库获取数据。
  • 图片、css、js 等存在服务器某个文件夹下的静态文件。

对于前一种请求,博客文章的数据需要借助 Django 从数据库中获取,Nginx 处理不了,它就会把这个请求转发给 Django,让 Django 去处理。而对于后一种静态文件的请求,只需要去这些静态文件所在的文件夹获取,Nginx 就会代为处理,不再麻烦 Django。

用 Django 去获取静态文件是很耗时的,但 Nginx 可以很高效地处理,这就是我们要使用 Nginx 的原因(当然其功能远不止这些)。

通过前面的步骤我们已经安装了 Nginx,并且已经把域名和服务器 IP 绑定了。运行下面的命令启动 Nginx 服务:

yangxg@localhost:~$ sudo service nginx start

在浏览器输入域名,看到如下页面说明 Nginx 启动成功了。

未分类

部署代码

部署前的项目配置

Django 项目中会有一些 CSS、JavaScript 等静态文件,为了能够方便地让 Nginx 处理这些静态文件的请求,我们把项目中的全部静态文件收集到一个统一的目录下,这个目录通常位于 Django 项目的根目录,并且命名为 static。为了完成这些任务,需要在项目的配置文件里做一些必要的配置:

blogproject/settings.py

# 其他配置...

STATIC_URL = '/static/'
# 加入下面的配置

STATIC_ROOT = os.path.join(BASE_DIR, ‘static’)STATIC_ROOT 指明了静态文件的收集目录,即项目根目录(BASE_DIR)下的 static 文件夹。

为了安全起见,在生产环境下需要关闭 DEBUG 选项以及设置允许访问的域名。打开 settings.py 文件,找到 DEBUG 和 ALLOWED_HOSTS 这两个选项,将它们设置成如下的值:

blogproject/settings.py

DEBUG = False

ALLOWED_HOSTS = [‘127.0.0.1’, ‘localhost ‘, ‘.zmrenwu.com’]ALLOWED_HOSTS 是允许访问的域名列表,127.0.0.1 和 localhost 是本地访问的域名,.zmrenwu.com 是访问服务器的域名(换成你自己的域名)。域名前加一个点表示允许访问该域名下的子域名,比如 www.zmrenwu.com、test.zmrenwu.com 等二级域名同样允许访问。如果不加前面的点则只允许访问 zmrenwu.com。

项目还会依赖一些第三方 Python 库,为了方便在服务器上一次性安装,我们将全部依赖写入一个叫 requirements.txt 的文本文件中。激活本地的虚拟环境(如果你使用了虚拟环境的话),并进入项目的根目录,运行 pip freeze > requirements.txt 命令:

(blogproject_env) C:UsersyangxgWorkspaceblogproject>
pip freeze > requirements.txt

这时项目根目录下会生成了一个 requirements.txt 的文本文件,其内容记录了项目的全部依赖。

将代码上传到 GitHub

将代码上传到 GitHub 等代码托管平台,这样我们就可以方便地把代码拉取到服务器了。Git 和 GitHub 的使用相信你已经很熟悉了,这里就不赘述过程。如果不知道如何使用地话可以自行百度相关教程。
注意数据库文件不要上传!

设置服务器目录结构

接下来需要把代码上传到服务器了。我服务器上存放代码的目录结构一般是这样的:

/home/yangxg/
    sites/
        demo.zmrenwu.com/
            env/
            django-blog-tutorial/

一台服务器可能部署多个网站,所有网站代码都放在 sites/ 目录下。demo.zmrenwu.com/ 这个文件夹以网站的域名命名,便于区分。env/ 是 python 虚拟环境目录。django-blog-tutorial/ 是 Django 博客项目目录。

因此先来创建这个目录结构,注意目录名替换为你自己的域名,以后涉及到 demo.zmrenwu.com 的地方通常都要替换你自己的域名,后面就不再一一指出了,运行下面的命令,

yangxg@localhost:~$ mkdir -p ~/sites/demo.zmrenwu.com

这里 ~ 代表当前用户的 home 目录,即 /home/yangxg/。

接下来创建虚拟环境,先进入到 demo.zmrenwu.com 目录下,然后运行 virtualenv 命令创建虚拟环境:

yangxg@localhost:~$ cd ~/sites/demo.zmrenwu.com
yangxg@localhost:~/sites/demo.zmrenwu.com$ virtualenv --python=python3 env

注意这里使用 –python=python3 来指定克隆 Python3 的环境。因为 ubuntu 系统默认安装了 Python2,如果不特别指定的话 Virtualenv 默认克隆的是 Python2 的环境。

检查一下虚拟环境是否创建成功,运行 ls 命令列出当前目录下的文件和文件夹,看到 env 这个文件夹说明虚拟环境创建成功。

yangxg@localhost:~/sites/demo.zmrenwu.com$ ls
env

接着再从代码仓库把项目代码拉取过来,把 git clone 后的地址换成你自己的 GitHub 仓库地址!

yangxg@localhost:~/sites/demo.zmrenwu.com$ git clone https://github.com/zmrenwu/django-blog-tutorial.git

运行 ls 命令检查一下是否拉取成功:

yangxg@localhost:~/sites/demo.zmrenwu.com$ ls
django-blog-tutorial  env

多了 django-blog-tutorial 文件夹(文件夹名称由你的 GitHub 仓库名决定),说明拉取成功了。

安装项目依赖

激活虚拟环境,再进入到项目根目录,即 requirements.txt 所在的目录,安装项目的全部依赖:

yangxg@localhost:~/sites/demo.zmrenwu.com$ source env/bin/activate
(env) yangxg@localhost:~/sites/demo.zmrenwu.com$ cd django-blog-tutorial/
(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ pip install -r requirements.txt

收集静态文件

虚拟环境下继续运行 python manage.py collectstatic 命令收集静态文件到 static 目录下:

(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ python manage.py collectstatic

生成数据库

虚拟环境下继续运行 python manage.py migrate 命令创建数据库文件:

(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ python manage.py migrate

创建超级用户

虚拟环境下继续运行 python manage.py createsuperuser 命令创建一个超级用户,方便我们进入 Django 管理后台。这和本地开发时是一样的,具体请参照:在 Django Admin 后台文章。

(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ python manage.py createsuperuser

配置 Nginx

接下是配置 Nginx 来处理用户请求。

先在服务器的 /etc/nginx/sites-available/ 目录下新建一个配置文件,文件名我一般就设置为域名。写上下面的配置内容:
/etc/nginx/sites-available/demo.zmrenwu.com

server {
    charset utf-8;
    listen 80;
    server_name demo.zmrenwu.com; ①

    location /static { ②
        alias /home/yangxg/sites/demo.zmrenwu.com/django-blog-tutorial/static; 
    }

    location / { ③
        proxy_set_header Host $host;
        proxy_pass http://unix:/tmp/demo.zmrenwu.com.socket;
    }
}

① 服务的域名为 demo.zmrenwu.com。

② 所有URL 带有 /static 的请求均由 Nginx 处理,alias 指明了静态文件的存放目录。

③ 其它请求转发给 Django 处理。proxy_pass 后面使用了 unix 套接字,其作用是防止端口冲突,这里就不再详述。

至于怎么在服务器新建文件和写文件,请自行学习一点点 vi 编辑器的用法,这里也不一一讲解了。

我们在 /etc/nginx/sites-available/ 放置了配置文件,接下来需要创建一个符号链接,把这个配置文件加入到启用的网站列表中去,被启用网站的目录在 /etc/nginx/sites-enabled/,你可以理解为从 sites-available/ 目录下发送了一个配置文件的快捷方式到 sites-enabled/ 目录。具体命令如下:

(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ sudo ln -s /etc/nginx/sites-available/demo.zmrenwu.com /etc/nginx/sites-enabled/demo.zmrenwu.com

使用 Gunicorn

Gunicorn 一般用来管理多个进程,有进程挂了Gunicorn 可以把它拉起来,防止服务器长时间停止服务,还可以动态调整 worker 的数量,请求多的时候增加 worker 的数量,请求少的时候减少。
在虚拟环境下,安装 Gunicorn:

(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ pip install gunicorn

用 Gunicorn 启动服务器进程:

(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ gunicorn --bind unix:/tmp/demo.zmrenwu.com.socket blogproject.wsgi:application

浏览器输入域名,可以看到访问成功了!

自动启动 Gunicorn

现在 Gunicorn 是我们手工启动的,万一哪天服务器崩溃重启了又得重新手工启动。为此我们写一个自动启动脚本,这样当服务器重新启动后,脚本会帮我们重启 Gunicorn。先按 Ctrl + c 停止刚才启动的服务器进程。

写一个启动脚本,这样当服务器重启后能自动引导 Gunicorn 的启动。脚本位于 /etc/init/ 目录下,且脚本文件名必须以 .conf 结尾:

/etc/init/gunicorn-demo.zmrenwu.com.conf

start on net-device-up ①
stop on shutdown

respawn ②

setuid yangxg ③
chdir /home/yangxg/sites/demo.zmrenwu.com/django-blog-tutorial ④

exec ../env/bin/gunicorn --bind unix:/tmp/demo.zmrenwu.com.socket blogproject.wsgi:application ⑤

① start on net-device-up 确保只在服务器联网时才启动 Gunicorn。

② 如果进程崩溃了(比如服务器重启或者进程因为某些以外情况被 kill),respawn 将自动重启 Gunicorn。

③ setuid 确保以 yangxg 用户的身份(换成你自己的用户名)运行 Gunicorn 进程。

④ chdir 进入到指定目录,这里进入项目的根目录。

⑤ exec 执行进程,即开启服务器进程。

现在可以用 start 命令启动 Gunicorn 了:

sudo start gunicorn-demo.zmrenwu.com

以后如果更新了代码,只要运行下面的命令重启一下 Nginx 和 Gunicorn 就可以使新的代码生效了:

sudo service nginx reload
sudo restart gunicorn-demo.zmrenwu.com

使用 CDN 加快 Bootstrap 和 jQuery 的加载速度

我们的项目使用了 Bootstrap 和 jQuery,这两个文件我们是从本地加载的。如果服务器性能比较差的话,加载需要耗费很长的时间,网站打开的速度就变得无法忍受。我们使用 CDN 来加快加载速度。具体来说,替换 base.html 的几个静态文件的加载标签:

base.html

- <link rel="stylesheet" href="{% static 'blog/css/bootstrap.min.css' %}">
- <script src="{% static 'blog/js/jquery-2.1.3.min.js' %}"></script>
- <script src="{% static 'blog/js/bootstrap.min.js' %}"></script>
+ <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
+ <script src="https://cdn.bootcss.com/jquery/2.1.3/jquery.min.js"></script>
+ <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

这样网站访问的速度将大大提升!

部署过程自动化

在整个部署过程中我们运行了十几条命令,手动输入了 N 个字符。如果每次更新代码都要远程连接到服务器执行这些命令的话将变得非常麻烦。接下来的教程我们将介绍使用 Fabric 自动化整个部署过程。写好部署脚本后,只需要执行一条命令,就可以非常方便地自动完成整个部署。

连接postgresql的三种方式

假设我们拥有一个远端的数据库服务器,是需要连接才能去管理和获取数据的,那我们怎样才能去连接呢?

通过数据库管理软件(pgadmin)

这是一种非常常见也很方便的工具。

未分类

通过代码的方式(sequel gem)

require 'sequel'       #sequel是一个数据库管理gem
require 'pg'

# 下面是sequle 提供的连接数据的方式
DB = Sequel.postgres(:host => '121.201.xx.xxx', 
           :port => 59888, 
           :user => 'usename', 
           :password => '123456', 
           :database => 'database', 
           :max_connections => 20, 
           :pool_timeout => 30 
           )

# 下面就可以写获取数据的sql 语句了
sql = "select * from accounts"
DB[sql].all

通过终端连接

前提是你在本机已安装了postgresql
如果没有安装则: brew install postgres
然后终端输入: psql -h 121.201.xx.xxx -p 6xxxx -U usename -d database

-h 主机名
-p 端口号
-U 用户名
-d 数据库

未分类

debian8 安装postgresql 和 phpPgAdmin

安装软件包

sudo apt-get install postgresql postgresql-contrib

配置apache2

sudo vim /etc/apache2/conf-available/phppgadmin.conf

内容如下

<Directory /usr/share/phppgadmin>

DirectoryIndex index.php
AllowOverride None
Allow from all
# Only allow connections from localhost:
#Require local

<IfModule mod_php5.c>

查看页面

http://192.168.1.125/phppgadmin/

设置postgresql账号和密码

账号为test,密码为password

sudo -u postgres psql template1
template1=# create user test with password 'password' createdb createuser; 

成功登陆数据库

温馨提示:数据库一般不要让其他客户端直接连接,你可以提供http的接口或者其他方式,所以我这里也没有配置其他客户端连接。