使用LXD搭建Web网站
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~
介绍
Linux的容器是Linux的一组进程,通过使用Linux内核功能与系统隔离。它是一个类似于虚拟机的构造,但它的更轻量级。您可以在同一台服务器上轻松创建多个容器。使用Linux容器,您可以在同一服务器上运行多个实例,或者将应用程序及其依赖项捆绑到容器中,而不会影响系统的其余部分。
假设您有一台服务器,并且已为您的客户设置了多项服务,按照Web应用来说,每个Web站点都是Apache或NginxWeb服务器的同一实例的虚拟主机。但是对于Linux容器,每个网站都在其自己的容器中配置,并具有自己的Web服务器。我们可以使用LXD来创建和管理这些容器。LXD提供管生命周期的容器管理。
在本教程中,您将使用LXD在同一服务器上安装两个基于Nginx的网站,每个网站都限制在自己的容器中。然后,您将在第三个容器中安装HAProxy,该容器将充当反向代理。然后,您将网站路由到HAProxy容器,以便从Internet访问这两个网站。
准备
要完成本教程,您需要以下内容:
- 一台已经设置好可以使用
sudo
命令的非root账号的Ubuntu服务器,并且已开启防火墙。没有服务器的同学可以在这里购买,不过我个人更推荐您使用免费的腾讯云开发者实验室进行试验,学会安装后在购买服务器。 - 两个域名,如果你没有域名,建议您先去这里注册一个域名,您需要将域名解析到您的服务器,您可以使用腾讯云云解析进行快速设置。
- 20GB以上存储空间,建议您使用腾讯云的云硬盘进行扩容。
第一步 - 将您的用户添加到lxd组
使用非root用户帐户登录服务器。我们将使用此帐户执行所有容器管理任务。为此,您必须先将此用户添加到lxd组。使用以下命令执行此操作:
sudo usermod --append --groups lxd sammy
注销服务器并重新登录,以便使用新的组成员身份更新新的SSH会话。登录后,您可以开始配置LXD。
第二步 - 配置LXD
需要先配置LXD才能使用,最重要的配置取决于存储容器的后端类型。LXD的推荐存储后端是ZFS文件系统,请安装zfsutils-linux
包:
sudo apt-get update
sudo apt-get install zfsutils-linux
安装完成后,您就可以初始化LXD了。在初始化期间,系统将提示您指定ZFS存储后端。接下来有两个部分,具体取决于您是要使用预分配文件还是块存储。按照适合您情况的步骤进行操作。指定存储机制后,您将为容器配置网络选项。
使用预分配的文件
请按照以下步骤配置LXD以使用预分配的文件来存储容器。首先,执行以下命令以启动LXD初始化:
sudo lxd init
系统将提示您提供信息,如以下输出所示。我们将选择默认值,包括预分配文件的建议大小。
Name of the storage backend to use (dir or zfs) [default=zfs]: zfs
Create a new ZFS pool (yes/no) [default=yes]? yes
Name of the new ZFS pool [default=lxd]: lxd
Would you like to use an existing block device (yes/no) [default=no]? no
Size in GB of the new loop device (1GB minimum) [default=15]: 15
Would you like LXD to be available over the network (yes/no) [default=no]? no
Do you want to configure the LXD bridge (yes/no) [default=yes]? yes
Warning: Stopping lxd.service, but it can still be activated by:
lxd.socket
LXD has been successfully configured.
建议的大小将根据服务器的可用磁盘空间自动计算。配置设备后,您将配置网络设置。
配置网络
初始化过程将为我们提供一个GUI,如下图所示,让我们为容器配置网络桥接,以便它们可以获取私有IP地址,相互通信以及访问网络。
使用每个选项的默认值,但当被问及IPv6网络时,请选择否,因为国内环境暂时不允许。
完成网络配置后,您就可以创建容器了。
第三步 - 创建容器
我们已成功配置LXD。我们指定了存储后端的位置,并为任何新创建的容器配置了默认网络。我们将准备创建和管理一些容器,我们将使用lxc命令。
让我们尝试我们的第一个命令,它列出了可用的已安装容器:
lxc list
您将看到以下输出:
Generating a client certificate. This may take a minute...
If this is your first time using LXD, you should also run: sudo lxd init
To start your first container, try: lxc launch ubuntu:16.04
+------+-------+------+------+------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+------+-------+------+------+------+-----------+
由于这是lxc
命令第一次与LXD管理程序通信,因此输出让我们知道该命令会自动创建客户端证书与LXD进行安全通信。然后,它显示了有关如何启动容器的一些信息。最后,该命令显示了一个空的容器列表,这很正常,我们尚未创建任何容器。
让我们来创建三个容器。我们将创建两个web容器,并为反向代理创建第三个容器。反向代理的目的是将来自网络的传入连接定向到容器中的正确Web服务器。
我们将使用lxc launch
命令创建并启动名为web1的Ubuntu 16.04(ubuntu:x
)容器。ubuntu:x
是预先配置的LXD镜像存储库的标识符
注意:您可以通过运行lxc image list images:
来运行镜像, lxc image list ubuntu:
命令找到所有可用Ubuntu映像的完整列表。
执行以下命令以创建容器:
lxc launch ubuntu:x web1
lxc launch ubuntu:x web2
lxc launch ubuntu:x haproxy
因为这是我们第一次创建容器,所以第一个命令从网络下载容器映像。接下来的两个容器创建速度要快得多。
在这里,您可以看到创建容器web1
的示例输出结果。
Creating web1
Retrieving image: 100%
Starting web1
现在我们已经创建了三个空的vanilla容器,让我们使用lxc list
命令来显示有关它们的信息:
lxc list
输出结果显示为一个表,其中包含每个容器的名称,其当前状态,IP地址,类型以及是否存在快照。
+---------+---------+-----------------------+------+------------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+---------+---------+-----------------------+------+------------+-----------+
| haproxy | RUNNING | 10.10.10.10 (eth0) | | PERSISTENT | 0 |
+---------+---------+-----------------------+------+------------+-----------+
| web1 | RUNNING | 10.10.10.100 (eth0) | | PERSISTENT | 0 |
+---------+---------+-----------------------+------+------------+-----------+
| web2 | RUNNING | 10.10.10.200 (eth0) | | PERSISTENT | 0 |
+---------+---------+-----------------------+------+------------+-----------+
记下容器名称及其对应的IPv4地址。您需要它们来配置您的服务。
第四步 - 配置Nginx容器
让我们连接到web1
容器并配置第一个Web服务器。
要进行连接,我们使用 lxc exec
命令,该命令需要容器的名称和要执行的命令。执行以下命令以连接到容器:
lxc exec web1 -- sudo --login --user ubuntu
--
字符串表示该命令参数lxc
应该停在那里,如在容器内将要执行的命令的行的其余部分将被传递。该命令是sudo --login --user ubuntu
,它为容器内的预配置帐户ubuntu提供登录shell 。
注意:如果需要以root身份连接到容器,则可以使用
lxc exec web1 --/bin/bash
命令。
进入容器后,我们的shell提示现在如下所示。
ubuntu@web1:~$
容器中的这个ubuntu用户具有sudo
访问权限,并且可以在不提供密码的情况下运行sudo
命令。这个shell限制在容器的范围内。我们在此shell中运行的任何内容都保留在容器中,无法转义到主机服务器。
让我们更新容器内Ubuntu实例的包列表并安装Nginx:
sudo apt-get update
sudo apt-get install nginx
让我们编辑此站点的默认网页,并添加一些文本,清楚地表明该站点是在web1容器中托管的。打开文件/var/www/html/index.nginx-debian.html
:
sudo nano /var/www/html/index.nginx-debian.html
对文件进行以下更改:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx on LXD container web1!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx on LXD container web1!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
...
我们在两个地方编辑了文件,并在on LXD container web1上专门添加了文本。保存文件并退出编辑器。
现在注销容器并返回主机服务器:
logout
对web2
容器重复此步骤。登录,安装Nginx,然后编辑文件/var/www/html/index.nginx-debian.html
以及使用web2
。然后退出web2
容器。
让我们使用curl
来测试容器中的Web服务器是否正常工作。我们需要先前显示的Web容器的IP地址。
curl http://10.10.10.100/
输出结果应该是:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx on LXD container web1!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx on LXD container web1!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
...
同样测试第二个容器,使用curl
命令及其IP地址验证它是否也正确设置。配置好两个容器后,我们可以继续设置HAProxy。
第五步 - 配置HAProxy容器
我们将使用HAProxy设置这些容器的代理。根据我们使用的域名将流量引导至每个容器。我们将在后面的配置示例中使用example.com
。我们将在主机名example.com
和www.example.com
上提供第一个网站。第二个网站使用www2.example.com
。或用您自己的域名代替这些域名。
登录haproxy
容器:
lxc exec haproxy -- sudo --login --user ubuntu
更新安装包列表并安装HAProxy:
sudo apt-get update
sudo apt-get install haproxy
安装完成后,我们需要配置HAProxy。HAProxy的配置文件位于/etc/haproxy/haproxy.cfg
中。使用您喜欢的文本编辑器打开文件。
sudo nano /etc/haproxy/haproxy.cfg
首先,我们将对defaults
部分进行一些修改。我们将添加forwardfor
选项,以便保留Web客户端的真实源IP,并且我们将添加http-server-close
选项,从而实现会话重用和更低的延迟。
global
...
defaults
log global
mode http
option httplog
option dontlognull
option forwardfor
option http-server-close
timeout connect 5000
timeout client 50000
timeout server 50000
...
接下来,我们将配置前端指向我们的两个后端容器。添加一个新的frontend
部分名为www_frontend
,如下所示:
frontend www_frontend
bind *:80 # Bind to port 80 (www) on the container
# It matches if the HTTP Host: field mentions any of the hostnames (after the '-i').
acl host_web1 hdr(host) -i example.com www.example.com
acl host_web2 hdr(host) -i web2.example.com
# Redirect the connection to the proper server cluster, depending on the match.
use_backend web1_cluster if host_web1
use_backend web2_cluster if host_web2
使用acl
命令与Web服务器的主机名匹配,并将请求重定向到相应的backend
部分。
然后我们定义两个新的backend
部分,每个部分分别用于每个Web服务器,分别命名它们为web1_cluster
和web2_cluster
。将以下代码添加到文件中以定义backend:
backend web1_cluster
balance leastconn
# We set the X-Client-IP HTTP header. This is useful if we want the web server to know the real client IP.
http-request set-header X-Client-IP %[src]
# This backend, named here "web1", directs to container "web1.lxd" (hostname).
server web1 web1.lxd:80 check
backend web2_cluster
balance leastconn
http-request set-header X-Client-IP %[src]
server web2 web2.lxd:80 check
balance
选项表示负载均衡策略。在这种情况下,我们选择最少数量的连接。http-request
选项使用真实Web客户端IP设置HTTP标头。如果我们没有设置此标头,则Web服务器会将HAProxy IP地址记录为所有连接的源IP,从而使分析流量来源的位置。server
选项指定server(web1
)的任意名称,并跟着服务器的主机名和端口。
LXD为容器提供DNS服务器,因此 web1.lxd
解析为与web1
容器关联的IP。其他容器有自己的主机名,例如 web2.lxd
和haproxy.lxd
。
check
参数告诉HAPRoxy在Web服务器上执行运行状况。要测试配置是否有效,请运行以下命令:
/usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -c
输出结果应该是
Configuration file is valid
让我们重新加载HAProxy,以便它读取新配置。
sudo systemctl reload haproxy
现在注销容器以便返回主机。
logout
我们已将HAProxy配置为充当反向代理,将其在80
端口上接收的任何连接转发到其他两个容器中的相应Web服务器。让我们测试haproxy
将请求转发到正确的Web容器。请执行以下命令:
curl --verbose --header 'Host: web2.example.com' http://10.10.10.10
这会向HAProxy发出请求并设置HTTP host
标头,HAProxy应使用该标头将连接重定向到相应的Web服务器。
输出结果应该是
...
> GET / HTTP/1.1
> Host: web2.example.com
> User-Agent: curl/7.47.0
> Accept: */*
>
...
<
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx on LXD container web2!</title>
<style>
...
HAProxy正确转发请求并将其转发给web2容器。Web服务器提供了我们之前编辑的默认索引页面。现在让我们将外部请求路由到HAProxy,可以让全世界访问我们的网站。
第六步 - 将传入连接转发到HAProxy容器中
最后一个难题是将反向代理连接到网络。我们需要设置我们的服务器以将它从80
端口上的网络接收的任何连接转发到haproxy
容器中。
HAProxy安装在容器中,无法从Internet访问。为了解决这个问题,我们将创建一个iptables
转发连接的规则。
iptables命令需要两个IP地址:服务器的公共IP地址(your_server_ip
)和haproxy容器的私有IP地址(your_haproxy_ip
),您可以使用lxc list
命令获取该地址。
执行此命令以创建规则:
sudo iptables -t nat -I PREROUTING -i eth0 -p TCP -d your_server_ip/32 --dport 80 -j DNAT --to-destination your_haproxy_ip:80
这是命令分解的方式:
-t nat
指定我们正在使用该nat表。-I PREROUTING
指定我们将规则添加到PREROUTING链。-i eth0
指定接口eth0,它是Droplets上的默认公共接口。-p TCP
表明我们正在使用TCP协议。-d your_server_ip/32
指定规则的目标IP地址。--dport 80
:指定目标端口。-j DNAT
表明我们想要跳转到目标NAT(DNAT)。--to-destination your_haproxy_ip:80
表明我们希望请求使用HAProxy转到容器的IP地址。
最后,要保存iptables
命令以便在重新启动后重新应用它,我们将安装iptables-persistent
软件包:
sudo apt-get install iptables-persistent
安装软件包时,系统将提示您保存所有当前iptables
规则。如果您已设置了两个FQDN,那么您应该能够使用Web浏览器连接到每个网站。
要测试两个Web服务器是否实际可以从Internet访问,请使用以下curl命令从本地计算机访问每个Web服务器:
curl --verbose --header 'Host: example.com' 'http://your_server_ip'
curl --verbose --header 'Host: web2.example.com' 'http://your_server_ip'
这些命令使HTTP连接到服务器的公共IP地址,并添加一个HTTP头字段,--header其中包含HAProxy将用于处理请求的选项。
这是第一个curl命令的输出结果:
* Trying your_server_ip...
* Connected to your_server_ip (your_server_ip) port 80 (#0)
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
...
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx on LXD container web1!</title>
<style>
body {
...
这是第二个curl
命令的输出结果:
* Trying your_server_ip...
* Connected to your_server_ip (your_server_ip) port 80 (#0)
> GET / HTTP/1.1
> Host: web2.example.com
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
...
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx on LXD container web2!</title>
<style>
body {
...
在这两种情况下,都会显示正确的网站。
结论
您已经设置了两个网站,每个网站都在自己的容器中,并使用HAProxy重定向流量。您可以复制此过程以配置更多网站,每个网站都限制在自己的容器中。
您还可以在新容器中添加MySQL,然后安装像WordPress这样的CMS来运行每个网站。您还可以使用此过程来支持旧版本的软件。最后,LXD提供了对容器的完整状态进行快照的功能,这使得以后可以轻松地创建备份和回滚容器。此外,如果我们在两个不同的服务器上安装LXD,则可以通过Internet连接它们并在服务器之间迁移容器。更多Linux教程请前往腾讯云+社区学习更多知识。
参考文献:《How to Host Multiple Web Sites with Nginx and HAProxy Using LXD on Ubuntu 16.04》
问答
相关阅读
安全报告 | 2018上半年互联网恶意爬虫分析:从全景视角看爬虫与反爬虫
此文已由作者授权腾讯云+社区发布,原文链接:https://cloud.tencent.com/developer/article/1177656?fromSource=waitui
欢迎大家前往腾讯云+社区或关注云加社区微信公众号(QcloudCommunity),第一时间获取更多海量技术实践干货哦~
海量技术实践经验,尽在云加社区!
使用LXD搭建Web网站的更多相关文章
- 从零搭建Web网站
前言 工作也有几多年了,无论是身边遇到的还是耳间闻到的,多多少少也积攒了自己的一些经验和思考,当然,博主并没有太多接触高大上的分布式架构实践,相对比较零碎,随时补充.俗话说得好,冰冻三尺非一日之寒,滴 ...
- 2-19-使用apache搭建web网站
1 搭建一台测试web服务器 案例: 部门内部搭建一台WEB服务器,采用的IP地址和端口为192.168.10.34:80,首页采用index.html 文件.管理员E-mail地址为 xuegod@ ...
- 搭建 Web 网站常用技能
为软件创建专用数据库及其账号 create database if not exists gitea default charset = utf8mb4; grant ALL PRIVILEGES o ...
- 【LAMP】搭建Web网站过程中的记录【Ubuntu18.04+Apache2.4+PHP7.2+MySQL5.7】
全文使用的环境如题,主机使用的是腾讯云主机. 内容应该会是linux和apache这些所有部分都有一点,因为是遇见一个问题就记录一个. 配置LAMP环境 这部分可以参考这篇文章:https://www ...
- 使用CGIHTTPServer搭建简单网站
目录 一.前提准备 二.搭建web网站 如何快速搭建web网站?这个问题对于我这样的小白来说简直就是一脸懵逼毫无头绪.在学习python的过程接触到了 CGI 编程,至于CGI是什么?怎么运行的?这我 ...
- NodeJS学习笔记(一)——搭建开发框架Express,实现Web网站登录验证
JS是脚本语言,脚本语言都需要一个解析器才能运行.对于写在HTML页面里的JS,浏览器充当了解析器的角色.而对于需要独立运行的JS,NodeJS就是一个解析器.每一种解析器都是一个运行环境,不但允许J ...
- 搭建开发框架Express,实现Web网站登录验证
NodeJS学习笔记(一)——搭建开发框架Express,实现Web网站登录验证 JS是脚本语言,脚本语言都需要一个解析器才能运行.对于写在HTML页面里的JS,浏览器充当了解析器的角色.而对于需 ...
- 基于Flask框架搭建视频网站的学习日志(三)之原始web表单
基于Flask框架搭建视频网站的学习日志(三)1.原始Web 表单 本节主要用于体验一下前端后端直接数据的交互,样例不是太完善,下一节会加入Flash处理,稍微完善一下页面 (备注:建议先阅读廖雪峰老 ...
- 最详细的搭建web自动化测试网站,别再说你没有实战项目(文未有福利)
一步步教你搭建开源网站 环境准备: Tomcat shopping商城文件 jdk环境 Mysql环境 解压shopping.rar拷贝至tomcat/webapps 在navicat导入数据库db_ ...
随机推荐
- python爬虫入门(一)urllib和urllib2
爬虫简介 什么是爬虫? 爬虫:就是抓取网页数据的程序. HTTP和HTTPS HTTP协议(HyperText Transfer Protocol,超文本传输协议):是一种发布和接收 HTML页面的 ...
- 洛谷 P1054 解题报告
P1054 等价表达式 题目描述 明明进了中学之后,学到了代数表达式.有一天,他碰到一个很麻烦的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的 ...
- Unite Beijing 2018 参会简要分享
一. Training Day 主讲人:鲍建运 操作:马瑞 课程包括较为完整的功能,如灯光设置,角色动画控制,Cinemachine,Timeline,AI寻路,以及最新的Post Processin ...
- Web3与智能合约交互实战
写在前面 在最初学习以太坊的时候,很多人都是自己创建以太坊节点后,使用geth与之交互.这种使用命令行交互的方法虽然让很多程序员感到兴奋(黑客帝国的既视感?),但不可能指望普通用户通过命令行使用Dap ...
- define 的全部使用方法
typedef的总结,以下是引用的内容(红色部分是我自己写的内容). 用途一: 定义一种类型的别名,而不只是简单的宏替换.可以用作同时声明指针型的多个对象.比如: char* pa, pb; // 这 ...
- springboot+activemq中引入重发机制
一.简介 在使用activemq消息中间件进行消息队列传输时,总会由于各种原因导致消息失败. 一个经典的场景是一个生成者向Queue中发消息,里面包含了一组邮件地址和邮件内容.而消费者从Queue中将 ...
- java 修饰符的访问权限
private,public,protected,默认不写(firendly) 1.Class类的访问权限: public:可以供所有的类访问. 默认:默认可以称为friendly但是,java语言中 ...
- SSM-MyBatis-15:Mybatis中关联查询(多表操作)
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 先简单提及一下关联查询的分类 1.一对多 1.1单条SQL操作的 1.2多条SQL操作的 2.多对一 2.1单 ...
- React Native系列(6) - 编译安卓私有React-Native代码
为何要自己编译React Native安卓私有代码 我们在开发中遇到一个HTTP2的问题,React Native安卓客户端在和HTTP2支持的服务器通讯的过程中会有crash,见 React-Nat ...
- ASP.NET Core 2 学习笔记(一)
来势汹汹的.NET Core似乎要取代.NET Framework,ASP.NET也随之发布.NET Core版本.虽然名称沿用ASP.NET,但相对于ASP.NET确实有许多架构上的差异,可以说除了 ...