使用 Dockerfile 构建生产环境镜像
传统部署的坑:
1202 年了,如果你连 Docker 都不知道是什么,我建议买一本书看看——或者谷歌一下,博客已经写烂了。
为什么有这篇文章,是因为我在真正做容器化改造的时候,发现公司生产环境存在大量的坑:
- 传统虚拟机部署,基本依赖克隆或者手工编译。由于人力原因,SRE 历来单传,编译出来的 PHP、扩展等二进制版本不一致;
 - 项目开发人员痛苦不堪——他没办法模拟出接近于线上一致的环境(碰不到摸不着,各种扩展版本都要自己去编译);
 - 新人入职都会灵魂拷问你一句——我怎么把线上的代码跑起来?
 - ……
 
用什么 Linux 发行版?
Ubuntu 应该是全球用户量最多的发行版了,嗯我说的是桌面这一块,折腾过的人都知道,出问题的时候开机会有 “检测到系统错误” 的提示,另外,网上提供的配置或者各种疑难杂症,改了不一定能生效,而且你还不确定改了会不会影响到别的,反正我是不敢用的哈哈(Manjaro 真香)。
CentOS 应该是大家最熟悉的,也是我见过最多应用在生产环境中的。它给我的感觉就是非常稳定,并且网上的资料是一搜索就展现在你面前,而你对着资料改配置,重载就生效,不会搞出什么问题。
公司的生产环境清一色 CentOS 6,但 CentOS 6 已经被官方弃用,不再提供 yum 镜像源,这也意味着很多包你都安装不了,所以你只能升级到 CentOS 7。
问题来了,我能升级吗?
这不得不说到之前线上出现过一个故障:
公司有一台发布构建机器,用来做代码部署,机器上安装了 NodeJS、Go 编译器等,有一天前端的同事说向 SRE 同学提了一个需求:
升级 NodeJS 到 v10 版本,因为以前的 v6 版本太旧了,SRE 同学也没多想,发现 CentOS 6 机器要升级 glibc 才行,于是运维的同事就升级 glibc 之后,升级了 NodeJS;
过了段时间有人部署某服务,该服务使用了 结巴分词 ,部署完发现线上挂了……
嗯,线上环境的 glibc 版本比较低,编译机的 glibc 版本高,部署过去不兼容直接就是启动不了,还好当时回滚的够快
直接用 7 也不是不可以,统一就 OK,但要命的是,发现有些祖传的 PHP 扩展,已经失传了,能兼容但是你怎么保证不出问题对不对?
经历万般挫折,最终使用的是 CentOS 6.9,好在腾讯云有 yum 源,东拼西凑了生产环境的 PHP 扩展之后,开发环境已经完美投入使用。
就是因为这些事情,前前后后花了两三周的时间都在折腾镜像。
小而美 VS 大而全:
CentOS 是真的大!我自己也使用 7 重新打了一个镜像,发现不管怎么清理各种缓存,最终的镜像大小都接近 1G!
虽然说也不是不能用,但我就是有洁癖呀。最后还是选择了 alpine ,把体积减少到 100M 以内。
到这里可能有人问:我们生产环境用的 alpine 也就 60M 左右,没有那么大吧?
之前看过这个项目 Laradock ,它的特点是定制化非常强,基本都是打开一些环境变量就可以构建出你所要的镜像;
但我更倾向于,牺牲一些磁盘空间,制作一个统一的环境。为了方便,线上没必要按照项目复制扩展,维护自己的 Dockerfile,统一都放进去就好了,维护起来也比较方便。
生产环境使用什么版本?
公司目前大量使用 PHP 5.4 和 PHP 7.2,扩展版本比较混乱;
没有直接使用 nginx,而是使用 openresty 1.11.2(主要是传统 IDC 部署缺乏云上 WAF ,需要自行做好限流和 IP 防刷);
我提供的 Dockerfile 是 PHP 5.6 和 PHP 7.2 的最新版本,理论上可以直接升级;而 openresty 使用最新奇数版本,保证生产环境的稳定和安全。
一些细节(坑):
记录一下为什么要花这么长的时间整这个镜像,个人觉得下面列举出来的,都是非常宝贵的经验:
镜像:
- 尽量合并 RUN 指令,减少镜像层数,从而缩小镜像体积;
 
apk:
- 官方的镜像非常慢,所以使用了阿里云的镜像加速;
 - apk --no-cache 的使用,也可以缩小镜像体积,对于自己安装的扩展不要忘记 rm 掉没用的文件夹;
 - composer 安装私有仓库依赖 git 命令,所以它需要被安装;
 - git clone 私有仓库需要 ssh-key,我的实现方式是 base64 编码文件内容,再 echo 到对应的位置上去,这样的好处就是一个 Dockerfile 就可以到处走了,不需要额外的文件和 COPY 指令,既方便又减少层数!
 - 通过 apk 安装下来的扩展,需要手工 cp 到 /usr/local/lib/php/extensions/no-debug-non-zts-20131226/ 目录下;
 
文件权限:
- 私钥的文件权限是 600,只有文件的拥有者具有读写权限,组里其他用户或者其他用户连读都不行,不这样做的话代码拉不下来(ssh 会报错),切记;
 
线上排障:
- bind-tools 的作用在于方便线上定位问题——有时候你不得不进去容器,发现没办法测试 DNS 解析,你会特别痛苦;
 
环境标准化:
- 统一应用目录 /www 和日志目录 /wwwlog;
 
文件权限:
- 用户和用户组的 id,此处是 500(CentOS 6),CentOS 7 是 1000——如果你使用 NFS 共享文件系统,需要统一 www 的 uid,不然文件权限问题会令你抓狂;
 - 公司使用 www 用户,官方提供的 fpm 镜像自带 www-data 用户,我代码重度洁癖,所以就把它删了;
 - 定时任务建议使用 www 用户运行,原因是日志目录有可能是被运维的同事挂在到宿主机采集(一台宿主机一个 filebeat 进程,节省资源),而你使用 root 用户创建的某些文件夹,其他人可能写不进去,但还是留了后手——给 root 设置密码,遇到问题说不定可以 su 解决;
 
扩展:
- 公司重度使用 RabbitMQ 消息队列组件,所以安装了 amqp 扩展,rabbitmq-c-dev 等基础包必须加上,不然没办法编译通过;
 - redis、bcmath、gettext、pdo_mysql、mysqli、mbstring、gd、zip、opcache 这几个扩展几乎都是必装的,其他的像 yaf、sysvmsg 等不需要的,大家可以自行删除;
 
php-fpm.conf:
- 非常驻模式启动,容器才不会刚启动就退出了;
 - 修改子进程数量,还有超时等配置,这部分与线上环境是一致的;
 
php.ini:
- 打开 cli 模式的 opcache 扩展,加速 PHP 的运行,主要是一些定时任务;
 - 关闭 PHP 的版本输出,这样别人访问我的网站就不知道我使用哪个 PHP 版本了,安全无小事!
 
适用于生产环境的 PHP 5 Dockerfile:
FROM php:5.6.40-fpm-alpine3.8
LABEL maintainer="??? <???@???.com>"
ENV TZ=Asia/Shanghai
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
    # deps
    apk --no-cache add bind-tools \
        git \
        make \
        openssh-client \
        php5-mcrypt \
        php5-sysvmsg \
        php5-sysvsem \
        php5-sysvshm \
        tzdata \
        freetype-dev \
        gettext-dev \
        imagemagick-dev \
        libmemcached-dev \
        libpng-dev \
        libzip-dev \
        jpeg-dev \
        rabbitmq-c-dev \
        && \
    cp /usr/lib/php5/modules/mcrypt.so  /usr/local/lib/php/extensions/no-debug-non-zts-20131226/ && \
    cp /usr/lib/php5/modules/sysvmsg.so /usr/local/lib/php/extensions/no-debug-non-zts-20131226/ && \
    cp /usr/lib/php5/modules/sysvsem.so /usr/local/lib/php/extensions/no-debug-non-zts-20131226/ && \
    cp /usr/lib/php5/modules/sysvshm.so /usr/local/lib/php/extensions/no-debug-non-zts-20131226/ && \
    # DNS
    [ ! -e /etc/nsswitch.conf ] && echo 'hosts: files dns' > /etc/nsswitch.conf && \
    # timezone
    ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
    echo '$TZ' > /etc/timezone && \
    # /www
    # /wwwlog
    # /app
    addgroup -g 500 -S www && \
    adduser -u 500 -D -S -G www www && \
    mkdir /www && mkdir /wwwlog && mkdir -p /app && \
    chown -R www:www /www && chown -R www:www /wwwlog && chown -R www:www /app && \
    addgroup www tty && \
    sed -i 's/\/home\/www:\/bin\/false/\/home\/www:\/bin\/ash/g' /etc/passwd && \
    deluser --remove-home www-data && \
    # password
    passwd root -d "!!!Production!!!" && \
    passwd www  -d "!!!Production!!!" && \
    # ssh-key
    mkdir -p /root/.ssh && \
    echo ???==|base64 -d>/root/.gitconfig && \
    echo ???==|base64 -d>/root/.ssh/config && \
    echo ???==|base64 -d>/root/.ssh/id_rsa && \
    echo ???==|base64 -d>/root/.ssh/id_rsa.pub && \
    echo ???==|base64 -d>/root/.ssh/known_hosts && \
    chmod 600 /root/.ssh/id_rsa && \
    # composer
    wget -O /usr/local/bin/composer https://mirrors.cloud.tencent.com/composer/composer.phar && \
    chmod +x /usr/local/bin/composer && \
    /usr/local/bin/composer config -g repos.packagist composer https://mirrors.cloud.tencent.com/composer/ && \
    # ext
    docker-php-ext-configure zip --with-libzip && \
    docker-php-ext-configure gd --with-jpeg-dir=/usr/lib --with-freetype-dir=/usr/include/freetype2 && \
    pecl install -o -f amqp-1.10.2 && \
    pecl install -o -f memcached-2.2.0 && \
    pecl install -o -f imagick-3.4.4 && \
    pecl install -o -f rar-4.2.0 && \
    pecl install -o -f redis-4.3.0 && \
    pecl download yaf-2.3.5 && tar zxvf yaf-2.3.5.tgz && cd yaf-2.3.5 && phpize && ./configure && \
    make && make install && cd .. && rm -rf yaf-2.3.5 && \
    docker-php-ext-install bcmath gettext mysqli pcntl sockets pdo_mysql mysqli mbstring gd zip opcache && \
    docker-php-ext-enable amqp mcrypt memcached imagick rar redis sysvmsg sysvsem sysvshm yaf && \
    rm -rf /tmp/pear /var/cache/apk/* /tmp/* && \
    # php-fpm.conf
    echo "[global]"        > /usr/local/etc/php-fpm.d/zz-docker.conf && \
    echo "daemonize = no" >> /usr/local/etc/php-fpm.d/zz-docker.conf && \
    # www.conf
    rm -f /usr/local/etc/php-fpm.d/www.conf.default && \
    sed -i "s/www-data/www/g"                                                  /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/pm.max_children = 5/pm.max_children = 128/g"                     /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/listen = 127.0.0.1:9000/listen = 127.0.0.1:9056/g"               /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/;pm.max_requests = 500/pm.max_requests = 1024/g"                 /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/;request_slowlog_timeout = 0/request_slowlog_timeout = 5/g"      /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/;request_terminate_timeout = 0/request_terminate_timeout = 30/g" /usr/local/etc/php-fpm.d/www.conf && \
    sed -i 's/;slowlog = log\/\$pool.log.slow/slowlog = \/proc\/self\/fd\/2/g' /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/;access.format/access.format/g"                                  /usr/local/etc/php-fpm.d/www.conf && \
    # php.ini
    cp /usr/local/etc/php/php.ini-production                 /usr/local/etc/php/php.ini && \
    sed -i "s/;opcache.enable_cli=0/opcache.enable_cli=1/g"  /usr/local/etc/php/php.ini && \
    sed -i "s/expose_php = On/expose_php = Off/g"            /usr/local/etc/php/php.ini
WORKDIR /app
适用于生产环境的 PHP 7 Dockerfile:
FROM php:7.2.34-fpm-alpine3.12
LABEL maintainer="??? <???@???.com>"
ENV TZ=Asia/Shanghai
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
    # deps
    apk update && \
    apk --no-cache add bind-tools \
        git \
        make \
        openssh-client \
        tzdata \
        freetype-dev \
        libmemcached-dev \
        libpng-dev \
        jpeg-dev \
        && \
    # DNS
    [ ! -e /etc/nsswitch.conf ] && echo 'hosts: files dns' > /etc/nsswitch.conf && \
    # timezone
    ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
    echo '$TZ' > /etc/timezone && \
    # /www
    # /wwwlog
    # /app
    addgroup -g 500 -S www && \
    adduser -u 500 -D -S -G www www && \
    mkdir /www && mkdir /wwwlog && mkdir -p /app && \
    chown -R www:www /www && chown -R www:www /wwwlog && chown -R www:www /app && \
    addgroup www tty && \
    sed -i 's/\/home\/www:\/sbin\/nologin/\/home\/www:\/bin\/ash/g' /etc/passwd && \
    deluser --remove-home www-data && \
    # password
    passwd -u root -d "!!!Production!!!" && \
    passwd -u www  -d "!!!Production!!!" && \
    # ssh-key
    mkdir -p /root/.ssh && \
    echo ???==|base64 -d>/root/.gitconfig && \
    echo ???==|base64 -d>/root/.ssh/config && \
    echo ???==|base64 -d>/root/.ssh/id_rsa && \
    echo ???==|base64 -d>/root/.ssh/id_rsa.pub && \
    echo ???==|base64 -d>/root/.ssh/known_hosts && \
    chmod 600 /root/.ssh/id_rsa && \
    # composer
    wget -O /usr/local/bin/composer https://mirrors.cloud.tencent.com/composer/composer.phar && \
    chmod +x /usr/local/bin/composer && \
    /usr/local/bin/composer config -g repos.packagist composer https://mirrors.cloud.tencent.com/composer/ && \
    # ext
    docker-php-ext-configure gd --with-jpeg-dir=/usr/lib --with-freetype-dir=/usr/include/freetype2 && \
    pecl install -o -f memcached-3.1.5 && \
    pecl install -o -f redis-5.3.4 && \
    docker-php-ext-install bcmath pdo_mysql gd opcache && \
    docker-php-ext-enable memcached redis && \
    rm -rf /tmp/pear /var/cache/apk/* /tmp/* && \
    # php-fpm.conf
    echo "[global]"        > /usr/local/etc/php-fpm.d/zz-docker.conf && \
    echo "daemonize = no" >> /usr/local/etc/php-fpm.d/zz-docker.conf && \
    # www.conf
    rm -f /usr/local/etc/php-fpm.d/www.conf.default && \
    sed -i "s/www-data/www/g"                                                  /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/pm.max_children = 5/pm.max_children = 256/g"                     /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/listen = 127.0.0.1:9000/listen = 127.0.0.1:9072/g"               /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/;pm.max_requests = 500/pm.max_requests = 1000/g"                 /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/;request_slowlog_timeout = 0/request_slowlog_timeout = 5/g"      /usr/local/etc/php-fpm.d/www.conf && \
    sed -i "s/;request_terminate_timeout = 0/request_terminate_timeout = 30/g" /usr/local/etc/php-fpm.d/www.conf && \
    sed -i 's/;slowlog = log\/\$pool.log.slow/slowlog = \/proc\/self\/fd\/2/g' /usr/local/etc/php-fpm.d/www.conf && \
    # php.ini
    cp /usr/local/etc/php/php.ini-production                 /usr/local/etc/php/php.ini && \
    sed -i "s/;opcache.enable_cli=0/opcache.enable_cli=1/g"  /usr/local/etc/php/php.ini && \
    sed -i "s/expose_php = On/expose_php = Off/g"            /usr/local/etc/php/php.ini
WORKDIR /app
适用于生产环境的 openresty Dockerfile:
FROM openresty/openresty:1.19.3.2-alpine-apk
LABEL maintainer="??? <???@???.com>"
ENV TZ=Asia/Shanghai
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
    # deps
    apk update && \
    apk --no-cache add bind-tools \
        tzdata \
        && \
    # DNS
    [ ! -e /etc/nsswitch.conf ] && echo 'hosts: files dns' > /etc/nsswitch.conf && \
    # timezone
    ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
    echo '$TZ' > /etc/timezone && \
    # /www
    # /wwwlog
    # /app
    addgroup -g 500 -S www && \
    adduser -u 500 -D -S -G www www && \
    mkdir /www && mkdir /wwwlog && mkdir -p /app && \
    chown -R www:www /www && chown -R www:www /wwwlog && chown -R www:www /app && \
    addgroup www tty && \
    sed -i 's/\/home\/www:\/sbin\/nologin/\/home\/www:\/bin\/ash/g' /etc/passwd && \
    # password
    passwd -u root -d "!!!Production!!!" && \
    passwd -u www  -d "!!!Production!!!"
COPY conf/nginx.conf            /usr/local/openresty/nginx/conf/nginx.conf
pcre_jit             on;
user                 www www;
worker_processes     1;
error_log            /usr/local/openresty/nginx/logs/error.log error;
worker_rlimit_nofile 65535;
events {
    use                epoll;
    worker_connections 65535;
}
http {
    include      mime.types;
    default_type application/octet-stream;
    server_tokens off;
    sendfile      on;
    tcp_nopush    on;
    tcp_nodelay   on;
    server_names_hash_bucket_size 512;
    client_max_body_size          8m;
    client_header_buffer_size     32k;
    large_client_header_buffers   4 32k;
    proxy_buffers           32 128k;
    proxy_buffer_size       128k;
    proxy_busy_buffers_size 128k;
    client_body_timeout   10;
    client_header_timeout 10;
    send_timeout          30;
    keepalive_timeout     60;
    log_format main escape=json '{"@timestamp":"$time_iso8601",'
                                 '"scheme":"$scheme",'
                                 '"remote_host":"$host",'
                                 '"clientip":"$remote_addr",'
                                 '"bytes":$body_bytes_sent,'
                                 '"cost":$request_time,'
                                 '"referer":"$http_referer",'
                                 '"agent":"$http_user_agent",'
                                 '"time_local":"$time_local",'
                                 '"xforward":"$http_x_forwarded_for",'
                                 '"method":"$request_method",'
                                 '"request":"$request_uri",'
                                 '"uri":"$uri",'
                                 '"postData":"$request_body",'
                                 '"cookieData":"$http_cookie",'
                                 '"httpversion":"$server_protocol",'
                                 '"reqid":"$reqid",'
                                 '"remote_port":"$remote_port",'
                                 '"server_port":"$server_port",'
                                 '"status":$status}';
    fastcgi_connect_timeout      300;
    fastcgi_send_timeout         300;
    fastcgi_read_timeout         300;
    fastcgi_buffer_size          64k;
    fastcgi_buffers              4 64k;
    fastcgi_busy_buffers_size    128k;
    fastcgi_temp_file_write_size 256k;
    fastcgi_intercept_errors     on;
    gzip              on;
    gzip_vary         on;
    gzip_comp_level   5;
    gzip_buffers      16 8k;
    gzip_min_length   1k;
    gzip_proxied      any;
    gzip_http_version 1.0;
    gzip_disable      "msie6";
    gzip_proxied      expired no-cache no-store private auth;
    gzip_types        text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/xml+rss application/json;
    server {
        listen      80 default_server;
        server_name _;
        return      444;
        access_log  /usr/local/openresty/nginx/logs/access.log main;
        include     add_header_reqid.conf;
    }
    include /usr/local/openresty/nginx/conf/vhost/*.conf;
}
嗯,真实的生产环境配置十分混乱,我做了格式化,大家拿去用吧
文章来源于本人博客,发布于 2021-06-13,原文链接:https://imlht.com/archives/236/
使用 Dockerfile 构建生产环境镜像的更多相关文章
- docker通过dockerfile构建JDK最小镜像,Docker导出导入镜像
		
docker通过dockerfile构建JDK最小镜像,Docker导出导入镜像 一.docker通过dockerfile构建JDK最小镜像 1.1 下载JRE 1.2 解压JRE,删除相关不需要文件 ...
 - 使用dockerfile构建自己的镜像
		
CentOS Linux release 7.2.1511 Docker version 17.03.1-ce 首先应该了解docker镜像的分层机制,这个网上文章很多,简单说就是对镜像的每次修改都是 ...
 - Docker使用Dockerfile构建新的镜像
		
构建镜像步骤; 1.创建Dockerfile文件,该文件是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明. vim Dockerfile //每一个指令都会在镜像上创建一个新 ...
 - Docker 使用 Dockerfile 构建自己的镜像
		
可以使用Dockerfile的配置文件方式进行构建自己的镜像 下面利用docker构建一个Caddy web服务器 构建脚本 Dockerfile有自己的命令,下面使用了一些比较常用的命令,更多的Do ...
 - 用k8s构建生产环境下应用服务
		
1.生成镜像 见https://www.cnblogs.com/mushou/p/9713741.html,把测试成熟的应用添加到tomcat镜像生成新的镜像,用ansible部署到集群的几点服务器中 ...
 - 【openstack N版】——手把手教你制作生产环境镜像
		
一.CentOS7镜像制作 1.1创建CentOS7虚拟机 1.1.1创建虚拟磁盘 #注:尽量将虚拟机创建在控制节点,以便于将镜像上传至glance [root@linux-node1 ~]# qem ...
 - 使用dockerfile构建镜像(docker build)
		
Docker buidl . 找出当前文件夹下的Docker build文件名的文件 Docker build -t centos(镜像名) . 在当前目录下找centos的镜像文件 Docker ...
 - 用Dockerfile构建docker image
		
dockerfile是为快速构建docker image而设计的,当你使用docker build 命令的时候,docker 会读取当前目录下的命名为Dockerfile(首字母大写)的纯文本文件并执 ...
 - 使用Docker构建jdk1.8镜像
		
一.下载centos镜像 下载自己需要的版本TAG,详见: docker安装指定版本TAG的镜像 $ sudo docker pull centos:centos7 二.下载jdk1.8,并上传到/u ...
 - Webpack配置区分开发环境和生产环境
		
在项目开发的时候,我们通常会将程序分为开发环境和生产环境(或者叫线上环境),开发环境通常指的是我们正在开发的这个阶段所需要的一些环境配置,也就是方便我们开发人员调试开发的一种环境:生产环境通常指的是我 ...
 
随机推荐
- 3.2 构造器、this、包机制、访问修饰符、封装
			
构造器 构造器:在实例化的一个对象的时候会给对象赋予初始值,因此我们可以通过修改构造器,来改变对象的初始值,构造器是完成对象的初始化,并不是创建对象 我们也可以创建多个构造器实现不同的初始化,即构造器 ...
 - 前端 本地缓存localStorage/sessionStorage
			
当我们刷新页面时,除了路由,页面的当前状态及数据会全部清空/重置,包括浏览器标题. 如果想保存刷新前的一些数据,可以通过window.localStorage/sessionStorage,在浏览器里 ...
 - Linux下七种文件类型、文件属性及其查看方法
			
1.七种文件类型 普通文件类型 Linux中最多的一种文件类型, 包括 纯文本文件(ASCII):二进制文件(binary):数据格式的文件(data);各种压缩文件.第一个属性为 [-] 目录文件 ...
 - AspNetCoreRateLimit应用于MVC项目求助
			
AspNetCoreRateLimit应用于MVC项目求助 前言 之前发过一篇文章: .NET Core WebApi接口ip限流实践 - 妙妙屋(zy) - 博客园 (cnblogs.com) 然后 ...
 - Grafana系列-统一展示-7-ElasticSearch数据源
			
系列文章 Grafana 系列文章 ElasticSearch 数据源 Grafana内置了对Elasticsearch的支持.你可以进行多种类型的查询,以可视化存储在Elasticsearch中的日 ...
 - 2022-08-28:把字符串 s 看作 “abcdefghijklmnopqrstuvwxyz“ 的无限环绕字符串, 所以 s 看起来是这样的: ...zabcdefghijklmnopqrstuv
			
2022-08-28:把字符串 s 看作 "abcdefghijklmnopqrstuvwxyz" 的无限环绕字符串, 所以 s 看起来是这样的: -zabcdefghijklmn ...
 - 2021-06-22:现有司机N*2人,调度中心会将所有司机平分给A、B两个区域,第 i 个司机去A可得收入为income[i][0],第 i 个司机去B可得收入为income[i][1],返回所有调
			
2021-06-22:现有司机N*2人,调度中心会将所有司机平分给A.B两个区域,第 i 个司机去A可得收入为income[i][0],第 i 个司机去B可得收入为income[i][1],返回所有调 ...
 - pyinstaller打包exe
			
1.执行环境说明 python版本3.7直接使用pip进行安装pywin32.pyinstallerpip install pywin32pip install pyinstaller 2.使用了第三 ...
 - uniapp 全局背景音乐播放+暂停(跳转页面不暂停)
			
最近需要一个功能 是在h5中播放小游戏的背景音乐,但是跳转界面之后音乐不暂停,就是跳转多个页面之后,音乐依然在播放,在游戏界面会有设置的静音的按钮,可以开启音乐和关闭音乐. 单独建了一个music.j ...
 - spring cloud gateway网关(一)之网关路由
			
1.gateway相关介绍 在微服务架构中,系统往往由多个微服务组成,而这些服务可能部署在不同机房.不同地区.不同域名下.这种情况下,客户端(例如浏览器.手机.软件工具等)想要直接请求这些服务,就需要 ...