使用Docker Compose部署Django和Vue.js应用

前言

本文主要内容关于使用docker-compose实践部署后端django-rest-framework和前端vue.js应用。记录其中遇到的一些坑以及解决办法。

准备Docker-compose环境

系统:Ubuntu 16.04(阿里云)代码中用户名:test

安装Docker

# install docker
## prepare
echo 'Preparing...'
sudo apt update
sudo apt upgrade -y
sudo apt install -y linux-image-extra-$(uname -r) linux-image-extra-virtual
## docker
echo 'Installing docker...'
sudo apt remove -y docker-ce docker-engine docker.io
wget -qO- http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh
sudo apt autoremove -y

sudo usermod -aG docker ${USER}

## docker Aliyun accelerator
## https://cr.console.aliyun.com/#/accelerator
echo 'Configuring docker registry mirrors...'
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://<your-own>.mirror.aliyuncs.com"]
}
EOF

exists(){
  command -v "$1" >/dev/null 2>&1
}

echo 'Installing docker-compose...'
if ! exists pip; then
    sudo apt install python-pip
fi
sudo python `which pip` install docker-compose

echo 'Restarting docker...'
sudo systemctl daemon-reload
sudo systemctl restart docker

部署

目录结构

.
├── .env // 环境变量
├── docker-compose.yml
├── backend // 放置后台django文件
├── frontend // 放置前端vue编译后代码
└── nginx // nginx相关配置
    ├── backend.conf
    ├── Dockerfile
    └── frontend.conf

具体配置

docker-compose.yml
version: '3'

services:
  web:
    restart: always
    build: ./backend
    expose:
      - "8000"
    volumes:
      - ./backend:/code
    env_file: .env
    links:
      - db
    depends_on:
      - db
    command: ["/code/wait-for-it.sh", "db:3306", "--", "bash","startup.sh"]
  nginx:
    restart: always
    build: ./nginx
    ports:
      - "80:80"
    volumes:
      - ./frontend:/usr/share/nginx/html/frontend:ro
      - ./backend/public:/usr/share/nginx//html/backend/public:ro
    links:
      - web
    depends_on:
      - web
  db:
    restart: always
    image: mysql:latest
    env_file: .env
    volumes:
      - ./data/initsql:/docker-entrypoint-initdb.d
      - ./data/db:/var/lib/mysql
    command: [mysqld, --character-set-server=utf8, --collation-server=utf8_unicode_ci]

第一次使用docker-compose部署,从网上参考了许多例子。但是由于docker-compose个版本的语法改动不小,遇到很多坑:

不同容器共享数据(host主机上的数据)

有些例子使用volumes_from,但是version 3已经删除该设置项更新变化。
官方推荐在根节点(与services同级)下配置volumes,但是没法映射到host主机的文件,有个插件local-persist可以做到,但是不想依赖第三方插件。只能使用麻烦点的写法:在每个service的volume设置项里重复映射host主机的文件

    web:
      volumes:
        - ./backend:/code
    nginx:
      volumes:
        - ./backend/public:/usr/share/nginx//html/backend/public:ro

不同容器互相通信

使用links实现容器间通信。配置需要访问的容器于links配置项下,没什么毛病。

容器启动顺序

实现容器按顺序启动,需要用到depends_on。

但是会有一个问题:depends_on只保证启动顺序,而我们的实际需求是:web容器启动的commands必须等到mysql完全启动,web容器的command才可以执行。因为我们加了restart: always,所以会导致web容器不断重启直到db容器启动完成。

我的解决办法是:给web容器的启动命令加上对mysql服务可用的查询,使用了一个查询脚本wait-for-it:

    command: ["/code/wait-for-it.sh", "db:3306", "--", "bash","startup.sh"]

环境变量

会有多个容器使用相同环境变量的情况,所以都放在.env文件里

    DEBUG=false

    MYSQL_HOST=db
    MYSQL_DATABASE=mydb
    MYSQL_ROOT_PASSWORD=mypass

关于Mysql官方镜像配置

  • 可以定义volume持久化数据库文件:
volumes:
- ./data/db:/var/lib/mysql
  • 如果有初始数据需要导入,可以定义volume映射到/docker-entrypoint-initdb.d:
volumes:
- ./data/initsql:/docker-entrypoint-initdb.d

注意: 该配置只有在/var/lib/mysql/下的mysql目录不存在时才会生效。也就是说,一旦容器启动过一次,之后就在也不会导入/docker-entrypoint-initdb.d里的文件,除非手动清空/var/lib/mysql/(或host主机的./data/db目录)。

关于Nginx容器配置

Dockerfile

    FROM nginx:alpine

    RUN rm /etc/nginx/conf.d/default.conf

    ADD frontend.conf /etc/nginx/conf.d/
    ADD backend.conf /etc/nginx/conf.d/

frontend.conf – vue app build files

    server {
        listen 80 deferred;
        server_name new.bylie.cn;

        root /usr/share/nginx/html/frontend;

        location / {
            try_files $uri $uri/ /index.html =404;
        }

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    }

backend.conf – django app

    server {
        # use 'listen 80 deferred;' for Linux
        # use 'listen 80 accept_filter=httpready;' for FreeBSD
        listen 80 deferred;
        client_max_body_size 5M;

        # set the correct host(s) for your site
        server_name service.bylie.cn;

        keepalive_timeout 5;

        location /public {
            root /usr/share/nginx/html/backend;
        }

        location / {
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            # enable this if and only if you use HTTPS
            # proxy_set_header X-Forwarded-Proto https;
            proxy_set_header Host $http_host;
            # we don't want nginx trying to do something clever with
            # redirects, we set the Host: header above already.
            proxy_redirect off;
            proxy_pass http://web:8000;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

备份数据库到host主机

docker-compose exec db sh -c 'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --databases ${MYSQL_DATABASE}' > ./backup/database.sql

关于django web容器配置

Dockerfile

    FROM python:3

    ENV PYTHONUNBUFFERED 1
    RUN mkdir /code
    WORKDIR /code
    ADD requirements.txt /tmp/
    RUN pip install -r /tmp/requirements.txt

启动脚本startup.sh

#!/usr/bin/env bash
python manage.py collectstatic --noinput &&
python manage.py migrate &&
gunicorn django_web_app.wsgi:application -w 2 -b :8000

当容器运行起来之后,可能需要导入一些初始数据或者fixtures,我写了一个init的django custom command,手动执行该command:

    docker-compose exec web python manage.py init

grep命令的基本用法

1. grep正则表达式(对文本行进行搜索过滤)

格式:grep [option] PATTERN [FILE...]
option:
        -i:忽略大小写
        -v:取反,显示未被匹配到的pattern
        -n:显示匹配的行号
        -c:统计匹配的行数
        -o: 只显示匹配到的pattern
        -q: 静默,不予显示
        -A#:after,匹配到的行再向后显示#行
        -B#:before,匹配到的行再向前显示#行
        -C#:context,向前向后各显示#行
        -E :等同于egrep(扩展的正则表达式)

2. 正则表达式元字符

字符匹配

.:任意单个字符
[]:匹配[]以内的任意单个字符
[^]:匹配[]以外的任意单个字符
[:digit:]:十进制数字
[:upper:]:大写字母
[:lower:]:小写字母
[:space:]:空格
[:alnum:]:字母及数字
[:alpha:]:大小写字母
eg:
[root@Centos6 ~]#grep r..t /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
[root@Centos6 ~]#grep r[a-z]t /etc/passwd
operator:x:11:0:operator:/root:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
[root@Centos6 ~]#grep r[^0-9][a-z]t /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

次数匹配

*:前面字符任意次
?:前面字符0或1次
.*:任意字符任意次
+:至少一次
{m,n}:大于m小于n次
*:前面字符任意次
[root@Centos6 ~]#grep ro*t /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
rtkit:x:499:499:RealtimeKit:/proc:/sbin/nologin
vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
?:前面字符0或1次
[root@Centos6 ~]#grep "ro?" /etc/passwd
root:x:0:0:root:/root:/bin/bash
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
.*:任意字符任意次
[root@Centos6 ~]#grep ro.*t /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
+:至少一次
[root@Centos6 ~]#grep "ro+" /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
rtkit:x:499:499:RealtimeKit:/proc:/sbin/nologin
{m,n}:大于m小于n次
[root@Centos6 ~]#grep "ro{1,5}" /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
systemd-bus-proxy:x:999:998:systemd Bus Proxy:/:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin
chrony:x:992:989::/var/lib/chrony:/sbin/nologin
setroubleshoot:x:991:988::/var/lib/setroubleshoot:/sbin/nologin
rooooot:x:1001:1001::/home/rooooot:/bin/bash
rooot:x:1002:1002::/home/rooot:/bin/bash

位置锚定

对于行来说
^:行首锚定
$:行尾锚定
^$:空行
^ $:空格
对于词来说
,b:词尾锚定
[root@Centos6 ~]#grep "^root" /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@Centos6 ~]#grep "bash$" /etc/passwd
root:x:0:0:root:/root:/bin/bash
mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/bash
ymd:x:500:500:ymd:/home/ymd:/bin/bash
[root@Centos6 ~]#grep "" /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/bash
ymd:x:500:500:ymd:/home/ymd:/bin/bash

分组

():将一个或多个字符作为一个整体,进行处理。
后向引用:引用前面分组括号中所匹配到的内容
1,2 ···
eg:
grep "(string1+(string2)*)"
1:string1+(string2)*
2:string2

扩展的正则表达式(egrep)

egrep等同于grep -E 其选项及参数大致与grep相同

字符匹配

.:任意单个字符
[]:匹配[]以内的任意单个字符
[^]:匹配[]以外的任意单个字符

次数匹配

*:前面字符任意次
?:前面字符0或1次
.*:任意字符任意次
+:至少一次
{m,n}:大于m小于n次

3、利用所学知识如何在生产环境中实现对磁盘最大使用空间的监控

在实际的生产环境中我们需要实时的查看及监控磁盘空间情况防止因磁盘空间不足导致服务器崩溃
因此我们需要查看磁盘利用率是否超过限制值。

此为利用现在所学的命令完成查看磁盘已使用的空间情况
[root@Centos6 ~]#df -h |grep "^/dev/sda"|tr -s " " | cut -d " " -f5|sort -nr|head -n1
10%

rhel 7.x设置VSFTPD允许匿名登陆

工作环境中的Server经常没有外网环境,需要自己搭建YUM源。

利用web总觉得会白白浪费一台主机,又不想改变端口,所以就喜欢用Vsftpd。

之前一直在centos 6.x环境上面装vsftpd。在/etc/vsftpd/vsftpd.conf中设置

anon_root=/mnt/ios

然后重启就可以匿名访问该目录了。

现在在rhel 7.x环境中安装vsftpd,同样在/etc/vsftpd/vsftpd.conf中设置

anon_root=/mnt/ios

我擦,竟然还要我账号密码登陆,后来简单的搜索了一下,发现是权限的锅,当文件的用户改为ftp时,解决此问题

ok,又能愉快的下载了。

Redis消息队列实现

消息队列

某次在某乎上看到有人提到消息队列的问题,然后有人在回答里提到了Redis,接着便有人在评论里指出:Redis是缓存,不是消息队列。

但不幸的是,Redis的确提供一个简易的消息队列机制,可以用于一些要求不那么高的场合。

方法就是利用Redis的列表类型的push和pop操作。

我对前文所介绍的Redis Cache作了一点简单的扩展,增加了消息队列功能。

实现

代码基本就这么点:

class RedisMQ(RedisCache):
    def __init__(self, dbname, host='localhost', port=6379, db=0):
        super(RedisMQ, self).__init__(dbname, host, port, db)

    def push(self, channel, data):
        ch = self._getkey("channel", channel)
        self.db.lpush(ch, self.SERIALIZER.dumps(data))

    def pop(self, channel, timeout=5):
        ch = self._getkey("channel", channel)
        msg = self.db.brpop(ch, timeout)
        return self.SERIALIZER.loads(msg[1]) if msg else None


class Channel(object):
    MQ = RedisMQ("msgqueue")

    def __init__(self, channel):
        self.channel = channel

    def push(self, **kwargs):
        Channel.MQ.push(self.channel, kwargs)

    def pop(self):
        return Channel.MQ.pop(self.channel)

用法

消息生产者

ch = Channel("test")
ch.push(a=123,b="hello")

消息消费者,可能是另一个线程,甚至是另一个进程,甚至是另外一台主机——只要它们共用同一个redis即可。

ch = Channel("test")
while msg=ch.pop():
    # msg: {"a": 123, "b": "hello"}
# ch is empty

CentOS7配置redis主从复制方法

1. 准备好4台机器

192.168.42.150 redis-node1 #主
192.168.42.151 redis-node2 #从 
192.168.42.152 redis-node3 #从
192.168.42.153 redis-node4 #从

将主机解析写入hosts文件,分发至每台机器

2. 安装redis,配置好基本配置

(1) 4台机器,分别安装redis

cd /usr/local/src
wget http://192.168.42.26/install_package/down/redis-3.2.3-1.el7.x86_64.rpm
yum install redis-3.2.3-1.el7.x86_64.rpm -y

(2) 4台机分别配置好,配置文件,做好备份

cp /etc/redis.conf{,.back}
vim redis.conf
daemonize yes
bind 192.168.42.150  #改为各个节点的IP

(3) 依照上面设定的从主机,在从主机配置文件中开启从配置(需要配置3台机器)

# slaveof <masterip> <masterport>
slaveof  192.168.42.150 6379

(4) 启动redis-server(4台同时启动)

redis-server /etc/redis.conf

(5) 在主机器上登录redis

[root@redis-node1 ~]# redis-cli -h 192.168.42.150
192.168.42.150:6379&gt; 
192.168.42.150:6379&gt; keys *
1) "magedu"
192.168.42.150:6379&gt; 
192.168.42.150:6379&gt; set ok "verygood!!!"
OK
192.168.42.150:6379&gt; get ok
"verygood!!!"
192.168.42.150:6379&gt;

登录其他3台从服务器

redis-cli -h 192.168.42.151
redis-cli -h 192.168.42.152
redis-cli -h 192.168.42.153
拿153做示例:
[root@redis-node4 src]# redis-cli -h 192.168.42.153
192.168.42.153:6379&gt; keys *
1) "magedu"
192.168.42.153:6379&gt; 
192.168.42.153:6379&gt; get ok
"verygood!!!"
192.168.42.153:6379&gt;

至此为至redis主/从已经实现,在主节点上查看信息

192.168.42.150:6379&gt; INFO Replication
# Replication
role:master
connected_slaves:3
slave0:ip=192.168.42.151,port=6379,state=online,offset=22806,lag=1
slave1:ip=192.168.42.152,port=6379,state=online,offset=22806,lag=1
slave2:ip=192.168.42.153,port=6379,state=online,offset=22806,lag=1
master_repl_offset:22806
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:22805

接下来在四个结点上配置sentinel,实现故障转移。此处实现累似于MariaDB的MHA 在上面我们已经配置好主从复制集群,现在我们需要添加一台机器[192.168.42.154]来做高可用 同样我们需要设置好,IP,主机名,下载安装redis

192.168.42.154 redis-sentinel  #将主机解析追加至其他的4台的hosts文件中,本机也需要一份
cd /usr/local/src
wget http://192.168.42.26/install_package/down/redis-3.2.3-1.el7.x86_64.rpm
yum install redis-3.2.3-1.el7.x86_64.rpm -y

(1)配置sentinel

# sentinel monitor     #法定人数
cp /etc/redis-sentinel.conf{,.back}
vim /etc/redis-sentinel.conf

daemonize yes
sentinel monitor mymaster 192.168.42.150 6379 1
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 18000
sentinel auth-pass mymaster centos.123 #这是认证选项,我们这里的主节点并没有开启认证

(2)启动sentinel

redis-sentinel /etc/redis-sentinel.conf

查看端口是否已经启动

[root@redis-sentinel src]# ss -tnl
State      Recv-Q Send-Q  Local Address:Port                 Peer Address:Port              
LISTEN     0      128                 *:22                              *:*                  
LISTEN     0      100         127.0.0.1:25                              *:*                  
LISTEN     0      511                 *:26379                           *:*                  
LISTEN     0      128                :::22                             :::*                  
LISTEN     0      100               ::1:25                             :::*                  
LISTEN     0      511                :::26379                          :::*

(3)模拟故障:

192.168.42.150:6379
pkill redis
#查看
[root@redis-node1 ~]# ss -tnl
State      Recv-Q Send-Q                             Local Address:Port                                            Peer Address:Port              
LISTEN     0      128                                            *:22                                                         *:*                  
LISTEN     0      100                                    127.0.0.1:25                                                         *:*                  
LISTEN     0      128                                           :::22                                                        :::*                  
LISTEN     0      100                                          ::1:25

(4)查看故障是否转移

登录192.168.42.151:6379 #巧了,恰好151变成主了
192.168.42.151:6379&gt; 
192.168.42.151:6379&gt; INFO Replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.42.153,port=6379,state=online,offset=5413,lag=1
slave1:ip=192.168.42.152,port=6379,state=online,offset=5413,lag=2
master_repl_offset:5413
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:5412
192.168.42.151:6379&gt; 

登录192.168.42.152:6379查看,的确是151变成主了
192.168.42.152:6379&gt; INFO Replication
# Replication
role:slave
master_host:192.168.42.151
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:11402
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
192.168.42.152:6379&gt;

(4)我们再把151的进程杀了,再来看一次,可以看到只有一主一从了

192.168.42.152:6379&gt; INFO Replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.42.153,port=6379,state=online,offset=1625,lag=1
master_repl_offset:1768
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:1767
192.168.42.152:6379&gt;

(5)最后我们将杀死的两台redis恢复,再来查看

192.168.42.152:6379&gt; INFO Replication
# Replication
role:master
connected_slaves:3
slave0:ip=192.168.42.153,port=6379,state=online,offset=12763,lag=1
slave1:ip=192.168.42.151,port=6379,state=online,offset=12763,lag=1
slave2:ip=192.168.42.150,port=6379,state=online,offset=12763,lag=0
master_repl_offset:12763
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:12762
192.168.42.152:6379&gt; 

可以看出此时的1主3从又回来了,不过此时主节点,是152

回到150,和151的节点查看效果
192.168.42.150:6379&gt; INFO Replication
# Replication
role:slave
master_host:192.168.42.152
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:23555
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
192.168.42.150:6379&gt; 



192.168.42.151:6379&gt; INFO Replication
# Replication
role:slave
master_host:192.168.42.152
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:20782
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

接下来我们配置有密码认证的主从和高可用

我们之前在配置sentinel,时还记得 #法定人数吗,判断为失效至少需要2个 Sentinel进程的同意,只要同意Sentinel的数量不达标,自动failover就不会执行

    sentinel monitor #法定人数

我们现在将154这台干脆也做成redis的从服务器,而sentinel,是这5台的集合(150,151,152,153,154)

(1).将153的配置文件推到154一份

scp /etc/redis.conf{,.back} [email protected]:/etc/
 到154这边稍微修改一下
 vim /etc/redis.conf
 bind 192.168.42.154

因此这次我们是要做密码认证的,因此5台机器都需要加上密码

(2).我们现在查看之前做了 sentinel后,配置文件系统自动帮我们改了,现在我们要恢复到初始状态,重新来过

所有的配置文件还需要设置我们的密码(为了方便管理,我们这里统一设置成magedu) requirepass magedu

所有从节点加上

#masterauth 
masterauth magedu
slaveof 192.168.42.150 6379

(3).密码设置好之后,启动所有服务

redis-server /etc/redis.conf
ss -tnl

登录150,需要认证了

[root@redis-node1 ~]# redis-cli -h 192.168.42.150
192.168.42.150:6379&gt; keys *
(error) NOAUTH Authentication required.

[root@redis-node1 ~]# redis-cli -h 192.168.42.150
192.168.42.150:6379&gt; keys *
(error) NOAUTH Authentication required.
192.168.42.150:6379&gt; keys *
(error) NOAUTH Authentication required.
192.168.42.150:6379&gt; AUTH magedu
OK

同样的,我们需要登录认证其他机器

再150机器上设置key
192.168.42.150:6379&gt; set zlyc "zai lai yi ci"
OK
192.168.42.150:6379&gt; get zlyc
"zai lai yi ci"
192.168.42.150:6379&gt; 

其他机器读取OK
192.168.42.151:6379&gt; get zlyc
"zai lai yi ci"
192.168.42.151:6379&gt;

解决phpmyadmin出现The mbstring extension is missing错误方法

这篇文章主要介绍了phpmyadmin提示The mbstring extension is missing的解决方法,分析了错误提示的原因与不同平台的解决方法,具有一定的参考借鉴价值,需要的朋友可以参考下

一、问题:

phpmyadmin提示:The mbstring extension is missing. Please check your PHP configuration.

二、解决方法:

其实只要运行一段:

yum install php-mbstring

就OK了。

如果用的是linux的话,可能是这个问题:查看一下 /etc/php5/mods-available/json.ini 这个文件,把第二行开头的分号去掉,也就是去掉注释,然后保存,重启php就可以了。

ubuntu mysql远程连接+phpmyadmin安装

一、如何让ubuntu上的mysql允许远程连接

进入MySQL,执行如下命令:

use mysql;

GRANT ALL PRIVILEGES ON *.* TO 'username'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION;

flush privileges; //刷新

select host,user from user; //查看是否成功

退出mysql;

  • 打开sudo vim /etc/mysql/my.cnf(可能不是此路径,也可能是my。conf,在该目录下找一下)
  • 将bind-address = 127.0.0.1
  • 设置成bind-address = 0.0.0.0(设备地址)

重新启动(命令如下):

sudo /etc/init.d/mysql restart

这样就可以远程连接了!

二、ubuntu如何安装phpmyadmin

方法一:

在phpmyadmin官网(https://www.phpmyadmin.net/)上下载压缩包,解压至你apache根目录下(默认/var/www/html),重命名为phpmyadmin;

sudo apt-get install php-mbstring php-gettext

然后修改PHP配置文件:

sudo vim /etc/php/7.0/apache/php/ini
display_errors = On(都改为On)
extension=php_mbstring.dll (去掉前面的;)

重启apache:

sudo /etc/init.d/apache2 restart

可以用http://localhost/phpmyadmin访问了!

方法二:

sudo apt-get install phpmyadmin

建立/var/www/html 下的软连接:

sudo ln -s /usr/share/phpmyadmin /var/www/html/phpmyadmin

安装php-mbstring和php.ini配置同方法一。

mysql5.7 phpMyAdmin Access denied for user ‘root’@’localhost’

遇到这种报错,先检查MySQL版本,如果是5.7的话,那默认是不允许phpmyadmin使用root登录的。
解决办法是,建立一个phpmyadmin专用账户,流程如下:

1. 进入mysql命令行

sudo mysql --user=root mysql

2. 创建phpmyadmin用户

CREATE USER 'phpmyadmin'@'localhost' IDENTIFIED BY '你的密码';
GRANT ALL PRIVILEGES ON *.* TO 'phpmyadmin'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;

3. 用刚才创建的用户登录即可

方法来自:https://askubuntu.com/questions/763336/cannot-enter-phpmyadmin-as-root-mysql-5-7

ubuntu14.04配置apache2 svn服务器(提供https访问)

一. 安装PHP

sudo apt-get install php5 libapache2-mod-php5 php5-mcrypt php5-curl php5-imagick php5-cli

二. 安装svn

输入安装命令:

sudo apt-get install subversion

(由于阿里云远程链接服务器时默认登陆管理员账号,所以sudo可以不用)
(如果无法下载软件,可能是由于阿里云可能把更新源的位置改了,运行apt-get update就行)

之后选择SVN服务文件及配置文件的放置位置。我放在了/srv下的svn目录。

sudo mkdir /srv/svn(版本仓库test)

目录建好后,创建版本仓库

sudo svnadmin create /srv/svn/test

执行之后test下文件结构如下:

未分类

三. 配置svn

跳转到配置文件

sudo cd /srv/svn/test/conf

1.修改svnserver.conf

sudo vi svnserve.conf
[general]
#匿名用户不可读
anon-access = none
#权限用户可写
auth-access = write
#密码文件为passwd
password-db = passwd
#权限文件为authz
authz-db = authz

这里修改时要顶格,不然要报错

2.authz 制定管理员组
即admin组的用户为admin,admin组对test有rw(读写权限)

[groups]
admin=admin       ##可以admin=admin,admin2,admin3

[test:/]
@admin=rw       ##admin组对test下的文件有读写权限

[:/项目/目录] #是以项目名作为第一个单位。不写版本库可以省略‘:’,即写成[/]
权限主体可以是用户组、用户或,用户组在前面加@,表示全部用户。权限可以是w、r、wr和空,空表示没有任何权限。

3.编制passwd文件,设定用户密码

[users]
admin=admin       ##用户名=密码

(注意等号两边不要留空格)

4.启动svn服务器

sudo svnserve -d -r /srv/svn/ --listen-port 3690

(这里启动服务时务必以管理员权限启动,否则用户拉取、提交文件时会提示权限不够)

-d 以守护模式启动

-r 制定svn版本库根目录,这样是便于客户端不用输入全路径,就可以访问版本库了

–listen-port 3690 监听3690端口,默认就是3690。。。所以不输也可以

5.访问代码库

svn://your ip/test
(查看IP地址:ifconfig)

注:到这里位置就可以通过svn访问了,通过https访问在后面

四. 安装apache2

输入安装命令:

sudo apt-get install apache2 apache2-utils libapache2-svn
sudo a2enmod ssl 开启SSL模块
sudo a2ensite default-ssl 启用SSL站点支持
sudo a2enmod rewrite 启用rewrite模块

1.配置/etc/apach2/apache2.conf

sudo vi /etc/apache2/apache2.conf

增加对.htaccess的支持:将www目录的AllowOverride参数修改为ALL
防止访问目录:将Options中的Indexes删除

2.重启apache服务

sudo /etc/init.d/apache2 restart

Apache的默认安装,会在/var下建立一个名为www的目录,这个就是Web目录了

  • 默认站点: /var/www/
  • 配置目录: /etc/apache2/
  • 日志目录: /var/log/apache/
  • 启动脚本: /etc/init.d/apache2

五. 配置自动更新

这里配置自动更新用的是svn的钩子,脚本是shell,也可以用其他的脚本比如python
钩子脚本的具体写法就是操作系统中shell脚本程序的写法,请根据自己SVN所在的操作系统和shell程序进行相应的写作
实现原理:当用户提交commit动作发生都让另外一处project马上从仓库中进行代码checkout一份出来!

1.在Web目录迁出代码

sudo svn co svn://127.0.0.1/test /var/www/html --username admin --password admin

2.添加脚本

在svn项目的hooks文件夹中的post-commit文件中添加脚本:用vi命令编辑一个新的post-commit(看清楚没有后缀名)千万不要用hooks文件夹里自带的post-commit文件,那是模板。

sudo vi /srv/svn/test/hooks/post-commit

在文件中添加如下内容:

#!/bin/sh
WEB=/var/www/html   #web服务器下的项目不能有空格。
#说明:post-commit会接受两个参数
REPOS="$1"  #/srv/svn/test  表示svn仓库的绝对路径值
REV="$2"  #表示最新的一个版本号。最后一个版本号
export LANG=en_US.UTF-8
svn update $WEB --username admin --password admin  #相当客户端的update操作
exit 0

如果不能判断自己写的shell脚本是否有错,可以现在hooks目录下运行./post-commit试一下

六. 配置https访问

1.安装OpenSSL

sudo apt-get install openssl

2.创建证书

sudo openssl req -x509 -newkey rsa:1024 -keyout apache.pem -out apache.pem -nodes -days 999

创建证书有两种方式:一种是自签名证书,一种是第三方CA机构签名证书。由于我们这里的证书只是保证传输数据安全性,因此我们使用自签名证书。

未分类

命令执行成功后会在当前目录生成一个apache.pem的证书,将这个文件复制到apache的配置目录/etc/apache2/ssl。

sudo mkdir /etc/apache2/ssl
sudo cp apache.pem /etc/apache2/ssl/

3.配置站点证书

sudo vi /etc/apache2/sites-available/default-ssl.conf
    SSLEngine on
    SSLCertificateFile    /etc/apache2/ssl/apache.pem
    #SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key

注意: SSLCertificateKeyFile前需要加#

如果配置没有问题,那么我们通过https协议就可以访问该IP地址了。

4.4配置apache服务器

/etc/apache2/mods-available/dav_svn.conf #加在文件最后面即可
<Location /svn >
DAV svn
#SVNPath /srv/svn/test
SVNParentPath /srv/svn
SVNListParentPath On
AuthType Basic
AuthName "welcome to subversion repository"
AuthUserFile /srv/svn/test/conf/passwd
AuthzSVNAccessFile /srv/svn/test/conf/authz
#<LimitExcept GET PROPFIND OPTIONS REPORT>
Require valid-user
SSLRequireSSL #(https,否则取消)
#</LimitExcept>
</Location>

5.添加新用户或修改老用户密码

htpasswd -c /etc/subversion/passwd 用户名 //第一次设置用户时使用-c表示新建一个用户文件,之后取消-c.
回车后输入用户密码

6.重启Apache

sudo service apache2 restart