软件工程相关环境配置
Contents
Docker
安装
在 Mac 链接、Windows 链接 下载安装程序,按照教程安装。
以 Mac 为例,安装完成打开后,在终端输入命令,可以看到 Docker 版本:
$ docker --version
Docker version 20.10.13, build a224086
镜像
考虑到科学上网等问题,建议为 Docker 添加国内镜像。
在 Docker 中点击 Preference...,选择 Docker Engine 选项卡,在其中添加一项 registry-mirrors
,填入一项网易镜像地址 http://hub-mirror.c.163.com
(其他镜像也可以自行添加):
{
"registry-mirrors": [
"http://hub-mirror.c.163.com"
],
"builder": {
"gc": {
"enabled": true,
"defaultKeepStorage": "20GB"
}
},
"debug": true,
"experimental": false
}
之后点击 Apply & Restart
按钮,在终端查看 Docker 信息:
$ docker info
...
Insecure Registries:
hubproxy.docker.internal:5000
127.0.0.0/8
Registry Mirrors:
http://hub-mirror.c.163.com/
...
可以看到镜像添加成功。
测试使用
以样例仓库 monolithic-example
为例,这是一个以 Django 为后端,React 为前端,前端通过 npm run build
预先构建得到静态 .js
文件用于 Django 的路由的前后端结合方式。
首先克隆仓库:
git clone git@git.tsinghua.edu.cn:SEG/example/monolithic-example.git
按照 README.md
中所述构建并运行 Docker(注意添加端口):
docker build -t something .
docker run -p 80:80 --rm something
然后在浏览器中输入 http://0.0.0.0/metrics
,我们将看到如下网页:
# HELP python_gc_objects_collected_total Objects collected during gc
# TYPE python_gc_objects_collected_total counter
python_gc_objects_collected_total{generation="0"} 969.0
python_gc_objects_collected_total{generation="1"} 850.0
python_gc_objects_collected_total{generation="2"} 231.0
...
这也就说明我们的 Docker 构建和运行成功了。
如果需要停止容器,可以新开启一个终端,使用:
docker ps -a
查找对应的 CONTAINER_ID
,并使用:
docker stop CONTAINER_ID
来停止容器。
开发环境
使用下列命令在 conda 中开启一个名为 example
的新虚拟环境:
conda create -n example python=3.8.5
安装依赖:
pip install -r requirements_dev.txt
如果出现了包安装错误,可考虑到 链接 安装对应的软件,并添加对应的 PATH
变量,以 Mac 为例:/Library/PostgreSQL/14/bin
。
Redis
Docker 中使用
新开一个文件夹 redis-example
,其中添加一个 Dockerfile
文件:
FROM redis:latest
EXPOSE 6379
COPY redis.conf /usr/local/etc/redis/redis.conf
CMD [ "redis-server", "/usr/local/etc/redis/redis.conf" ]
新建 redis.conf
文件,来源于 链接,可能需要修改的几个点是:
bind 127.0.0.1 -::1 # 需要注释才可以外部访问
# requirepass foobared # 取消注释 自己设置密码 建议设置
appendonly no # 设置为 yes 使得 redis 持久化
dir ./ # 设置本地数据库存放目录 可设置为形如 /data/ 并配合平台的挂载功能使用
运行下列命令以构建和运行容器:
docker build -t redis .
docker run -p 6379:6379 --rm redis
使用安装了 redis
包的 Python,运行脚本 test.py
:
import redis
pool = redis.ConnectionPool(host='127.0.0.1', port=6379, password='foobared')
r = redis.Redis(connection_pool=pool)
r.set('Age', 18)
print(r.get('Age'))
可以发现输出即为:
b'18'
符合预期。
后端配置
在 requirements.txt
中添加一行:
redis==4.1.4
重新安装依赖并重新 build 容器。
SECoder 使用
由于 Redis 自定义配置文件需要手动指定,所以需要考虑使用自定义镜像。
上传镜像
首先到 Docker Hub 上注册账号,在本地 Docker 登录后,使用上面类似的命令构建镜像并推送到 Docker Hub:
docker build -t <username>/redis .
docker push <username>/redis
其中 <username>
建议填写为注册的用户名(防止冲突)。
SECoder 部署与持久卷配置
在 SECoder 的部署管理界面,选择添加容器,填写自定义的容器名(如 redis
)和镜像(即上面的 <username>/redis:latest
),等待构建。
注:
- 如果不想这么麻烦,也可以直接使用我上传的镜像
wzf2000/redis
,密码为foobared
,数据目录为/data/
。如果需要自定义配置,比如数据目录等,建议还是推送一下镜像
添加一个持久存储,可命名为 redis-data
。
在刚添加的容器中挂载刚添加的持久存储,挂载点填写为上面配置中的 dir
值(如 /data
)。
注意开启对应的端口。
内网连接测试
等待容器重启后,打开一个带有 Python 环境的其他容器(比如后端容器)的终端,如果没有安装 redis
包,则先:
pip install redis
然后输入 python
进入 Python 的 CLI,依次输入以下命令测试:
import redis
pool = redis.ConnectionPool(host='<your-local-address>', port=6379, password='foobared')
r = redis.Redis(connection_pool=pool)
r.set('Age', 18)
print(r.get('Age'))
其中 <your-local-address>
替换为 Redis 容器的内网地址(形如 <container-name>.<group-name>.secoder.local
)。
我们将看到以下反馈,代表连接成功(这边可以重启 Redis 容器,确认 get
依然成功):
b'18'
Elastic Search
Docker 中使用
新开一个文件夹 es-example
,其中添加一个 Dockerfile
文件:
FROM elasticsearch:7.17.1
COPY elasticsearch.yml /usr/share/elasticsearch/config
# expose the default Elasticsearch port
EXPOSE 9200 9300
新建配置文件 elasticsearch.yml
(其中 path.data
对应地址可作为存储卷挂载):
# ---------------------------------- Cluster -----------------------------------
#
# Use a descriptive name for your cluster:
#
cluster.name: elasticsearch
#
# ------------------------------------ Node ------------------------------------
#
# Use a descriptive name for the node:
#
node.name: test
#
# Add custom attributes to the node:
#
#node.attr.rack: r1
#
# ----------------------------------- Paths ------------------------------------
#
# Path to directory where to store the data (separate multiple locations by comma):
#
path.data: /usr/share/elasticsearch/data
#
# Path to log files:
#
path.logs: /usr/share/elasticsearch/logs
#
# ----------------------------------- Memory -----------------------------------
#
# Lock the memory on startup:
#
#bootstrap.memory_lock: true
#
# Make sure that the heap size is set to about half the memory available
# on the system and that the owner of the process is allowed to use this
# limit.
#
# Elasticsearch performs poorly when the system is swapping the memory.
#
# ---------------------------------- Network -----------------------------------
#
# Set the bind address to a specific IP (IPv4 or IPv6):
#
network.host: 0.0.0.0
#
# Set a custom port for HTTP:
#
http.port: 9200
#
# For more information, consult the network module documentation.
#
# --------------------------------- Discovery ----------------------------------
#
# Pass an initial list of hosts to perform discovery when this node is started:
# The default list of hosts is ["127.0.0.1", "[::1]"]
#
#discovery.seed_hosts: ["host1", "host2"]
#
# Bootstrap the cluster using an initial set of master-eligible nodes:
#
#cluster.initial_master_nodes: ["node-1", "node-2"]
#
# For more information, consult the discovery and cluster formation module documentation.
#
# ---------------------------------- Gateway -----------------------------------
#
# Block initial recovery after a full cluster restart until N nodes are started:
#
#gateway.recover_after_nodes: 3
#
# For more information, consult the gateway module documentation.
#
# ---------------------------------- Various -----------------------------------
#
# Require explicit names when deleting indices:
#
#action.destructive_requires_name: true
discovery.type: single-node
运行下列命令以构建和运行容器:
docker build -t elasticsearch .
docker run -p 9200:9200 -p 9300:9300 --rm elasticsearch
之后在浏览器中输入 http://localhost:9200/
即可看到:
{
"name" : "test",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "OIu1eIjgTwSIzSyIxQZW0g",
"version" : {
"number" : "7.17.1",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "e5acb99f822233d62d6444ce45a4543dc1c8059a",
"build_date" : "2022-02-23T22:20:54.153567231Z",
"build_snapshot" : false,
"lucene_version" : "8.11.1",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
后端配置
在 requirements.txt
中添加一行:
elasticsearch==7.17.1
重新安装依赖并重新 build 容器。
SECoder 使用
由于 ES 中的配置文件目录下文件较多,直接挂载配置项难以保证剩余文件正常使用,所以需要考虑使用自定义镜像。
上传镜像
首先到 Docker Hub 上注册账号,在本地 Docker 登录后,使用上面类似的命令构建镜像并推送到 Docker Hub:
docker build -t <username>/elasticsearch .
docker push <username>/elasticsearch
其中 <username>
建议填写为注册的用户名(防止冲突)。
SECoder 部署与持久卷配置
在 SECoder 的部署管理界面,选择添加容器,填写自定义的容器名(如 elasticsearch
)和镜像(即上面的 <username>/elasticsearch:latest
),等待构建。
注:
- 如果不想这么麻烦,也可以直接使用我上传的镜像
wzf2000/elasticsearch
,对应的配置即为上述所写。如果需要自定义配置,比如数据目录等,建议还是推送一下镜像
添加一个持久存储,可命名为 es-data
。
在刚添加的容器中挂载刚添加的持久存储,挂载点填写为上面配置中的 path.data
值(如 /usr/share/elasticsearch/data
)。
注意开启对应的端口。
内网连接测试
等待容器重启后,打开一个带有 Python 环境的其他容器(比如后端容器)的终端,如果没有安装 elasticsearch
包,则先:
pip install elasticsearch==7.17.1
然后输入 python
进入 Python 的 CLI,依次输入以下命令测试:
from elasticsearch import Elasticsearch
from elasticsearch import AsyncElasticsearch
client = Elasticsearch("http://<your-local-address>:9200")
client.search(index='*')
其中 <your-local-address>
替换为 ES 容器的内网地址(形如 <container-name>.<group-name>.secoder.local
)。
我们将看到以下反馈,代表连接成功:
{'took': 0, 'timed_out': False, '_shards': {'total': 0, 'successful': 0, 'skipped': 0, 'failed': 0}, 'hits': {'total': {'value': 0, 'relation': 'eq'}, 'max_score': 0.0, 'hits': []}}
MySQL/MariaDB
Docker 中使用
直接使用 gjz010/mariadb:latest
作为镜像即可,注意查看初始日志记录初始密码,方便后续的登录调试。
后端配置
在 requirements.txt
中添加一行:
pymysql==1.0.2
重新安装依赖并重新 build 容器。
SECoder 使用
SECoder 部署
首先创建一个容器,容器名自取,镜像名为 gjz010/mariadb:latest
。
在端口处开放端口 3306,等待容器重启完毕后,打开容器的日志,在其中查找如下字段:
...
GENERATED ROOT PASSWORD: XXXXXX
...
将后面的 XXXXX
记录下来,即为自动随机生成的 root
账户初始密码。
持久卷部署
随后打开容器的终端,利用刚刚得到的密码登录 MySQL:
$ mysql -uroot -p
Enter password:
输入命令确定数据存储位置:
MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE 'datadir';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| datadir | /var/lib/mysql/ |
+---------------+-----------------+
1 row in set (0.001 sec)
可知数据存储在 /var/lib/mysql/
下。
通过持久卷存储挂载到此目录下,然后再次使用密码进入容器登录 MySQL 进行测试。
尝试创建一个数据库:
MariaDB [(none)]> create database test;
Query OK, 1 row affected (0.006 sec)
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
4 rows in set (0.002 sec)
完成后重启容器(可通过任意修改端口,注意操作不要太快,否则可能导致出现两个容器抢占存储卷),重新进入容器,登录 MySQL 测试:
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
4 rows in set (0.003 sec)
可以看到数据得以保存。
内网连接测试
打开一个带有 Python 环境的其他容器(比如后端容器)的终端,如果没有安装 pymysql
包,则先执行:
pip install pymysql
然后输入 python
进入 Python 的 CLI,依次输入以下命令测试:
import pymysql
db = pymysql.connect(host='<your-local-address>',
user='root',
password='<password>',
database='test')
cursor = db.cursor()
cursor.execute("DROP TABLE IF EXISTS EMPLOYEE")
sql = """CREATE TABLE EMPLOYEE (
FIRST_NAME CHAR(20) NOT NULL,
LAST_NAME CHAR(20),
AGE INT,
SEX CHAR(1),
INCOME FLOAT )"""
cursor.execute(sql)
db.close()
其中 <your-local-address>
替换为 MySQL 容器的内网地址(形如 <container-name>.<group-name>.secoder.local
),<password>
替换为之前得到的初始密码(或者自行修改后的密码)。
之后重新进入 MySQL 容器的终端,进行测试:
MariaDB [(none)]> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MariaDB [test]> show tables;
+----------------+
| Tables_in_test |
+----------------+
| EMPLOYEE |
+----------------+
1 row in set (0.000 sec)
MariaDB [test]> desc EMPLOYEE;
+------------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+----------+------+-----+---------+-------+
| FIRST_NAME | char(20) | NO | | NULL | |
| LAST_NAME | char(20) | YES | | NULL | |
| AGE | int(11) | YES | | NULL | |
| SEX | char(1) | YES | | NULL | |
| INCOME | float | YES | | NULL | |
+------------+----------+------+-----+---------+-------+
5 rows in set (0.001 sec)
可以发现,数据表建立成功。
单元测试
待补充。
No Comments