首页 文章 精选 留言 我的

精选列表

搜索[webpack入门],共10000篇文章
优秀的个人博客,低调大师

Docker入门-搭建docker私有仓库

Docker Hub 目前Docker官方维护了一个公共仓库Docker Hub,其中已经包括了数量超过15000个镜像。大部分需求都可以通过在Docker Hub中直接下载镜像来使用。 注册登录 可以在https://hub.docker.com 免费注册一个Docker账号。在命令行执行docker login输入用户名及密码来完成在命令行界面登记Docker Hub。你可以通过docker logout退出登录。 拉取镜像 可以通过docker search命令来查找官方仓库中的镜像,并利用docker pull命令来将它下载到本地。 推送镜像 用户也可以在登录后通过docker push命令来将自己的镜像推送到Docker Hub。 修改本地镜像的名字为账号名/镜像名 上传镜像到公共仓库 上传过后,查看远程公共仓库 私有仓库 有时候使用Docker Hub这样的公共仓库可能不方便,用户可以创建一个本地仓库供私人使用。比如,基于公司内部项目构建的镜像。docker-registry是官方提供的工具,可以用于构建私有的镜像仓库。 安装运行docker-registry 可以通过获取官方registry镜像来运行。默认情况下,仓库会被创建在容器的/var/lib/registry目录下。可以通过-v参数来将镜像文件存放在本地的指定路径。 docker run --name registry -d -p 5000:5000 --restart=always -v /opt/data/registry:/var/lib/registry registry 在私有仓库上传、搜索、下载镜像 创建好私有仓库之后,就可以使用docker tag来标记一个镜像,然后推送它到仓库。先在本机查看已有的镜像。 docker image ls 使用docker tag将session-web:latest这个镜像标记为127.0.0.1:5000/session-web:latest格式为docker tag IMAGE:TAG/]REPOSITORY[:TAG] docker tag session-web:latest 127.0.0.1:5000/session-web:latest 使用docker push上传标记的镜像 docker push 127.0.0.1:5000/session-web:latest 用curl查看仓库中的镜像 curl 127.0.0.1:5000/v2/_catlog 如果可以看到{"repositories":["session-web"]},表明镜像已经被成功上传了。 先删除已有镜像,再尝试从私有仓库中下载这个镜像。 docker image rm 127.0.0.1:5000/session-web:latest docker pull 127.0.0.1:5000/session-web:latest 注意事项 如果不想使用127.0.0.1:5000作为仓库地址,比如想让本网段的其他主机也能把镜像推送到私有仓库。你就得把例如192.168.1.1:5000这样的内网地址作为私有仓库地址,这时你会发现无法成功推送镜像。 可以用下面方式解决 对于使用systemd的系统,请在/etc/docker/daemon.json中写入如下内容(如果文件不存在请新建该文件) { "registry-mirror":[ "http://hub-mirror.c.163.com" ], "insecure-registries":[ "192.168.1.1:5000" ] }

优秀的个人博客,低调大师

Docker入门-常用命令

Docker镜像操作 Docker运行容器前需要本地存在对应的镜像,如果本地不存在该镜像,Docker会从镜像仓库下载该镜像。 获取镜像 从Docker镜像仓库获取镜像的命令是docker pull。其命令格式为: docker pull [选项][Docker Registry地址[:端口号]/]仓库名[:标签] 具体的选项可以通过docker pull --help命令看到,这里我们说一下镜像名称的格式。Docker镜像仓库地址:地址的格式一般是<域名/IP>[:端口号]。默认地址是Docker Hub。仓库名:如之前所说,这里的仓库名是两段式名称,即<用户名>/<软件名>。对于Docker Hub,如果不给出用户名,则默认为library,也就是官方镜像。 docker pull ubuntu:16.04 上面的命令中没有给出Docker镜像仓库地址,因此将会从Docker Hub获取镜像。而镜像名称是ubuntu:16.04,因此将会获取官方镜像library/ubuntu仓库中标签为16.04的镜像。 运行镜像 有了镜像后,我们就能够以这个镜像为基础启动并运行一个容器。以上面的ubuntu:16.04为例,如果我们打算启动里面的bash并且进行交互式操作的话,可以执行下面的命令。 docker run -it --rm ubuntu:16.04 bash -it:这是两个参数,一个是-i:交互式操作,一个是-t终端。 --rm:这个参数是说容器退出后随之将其删除 ubuntu:16.04:这是指用ubuntu:16.04镜像为基础来启动容器。 bash:放在镜像名后的是命令,这里我们希望有个交互式shell,因此用的是bash。 最后我们通过exit退出了这个容器。 列出镜像 要想列出已经下载下来的镜像,可以使用docker image ls命令。列表包含了仓库名、标签、镜像ID、创建时间以及所占用的空间。 docker image ls 查看镜像、容器、数据卷所占用的空间。 docker system df 仓库名、标签均为的镜像称为虚悬镜像(dangling image),显示这类镜像 docker image ls -f dangling=true 一般来说,虚悬镜像已经失去了存在的价值,是可以随意删除的,可以用下面的命令删除 docker image prune 删除本地镜像 如果要删除本地的镜像,可以使用docker image rm命令,其格式为: docker image rm [选项] <镜像1>[<镜像2>...] 其中,<镜像>可以是镜像短ID、镜像长ID、镜像名或者镜像摘要。 使用docker image ls -q来配置docker image rm,这样可以批量删除希望删除的镜像。 docker image rm $(docker image ls -q ubuntu) #删除所有仓库名为redis的镜像 或者删除所有在ubuntu:16.04之前的镜像: docker image rm $(docker image ls -q -f before=ubuntu:16.04) Docker容器操作 容器是独立运行的一个或一组应该,以及它们运行态环境。对应的,虚拟机可以理解为模拟运行的一整套操作系统(提供了运行态环境和其他系统环境)和跑在上面的应用。 启动容器 启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(stopped)的容器重新启动。 因为Docker的容器实是轻量级的,用户可以随时删除和新创建容器。 新建并启动 docker run 输出一个“Hello World”,之后终止容器。 docker run ubuntu:16.04 /bin/echo "Hello world" 启动已终止容器 docker container start 或者 docker start 启动一个bash终端,允许用户进行交互。 docker run -t -i ubuntu:16.04 /bin/bash -t 让Docker分配一个伪终端并绑定到容器的标准输入上,-i则让容器的标准输入保持打开。当利用docker run来创建容器时,Docker在后台运行的标准操作包括: 检查本地是否存在指定的镜像,不存在就从公有仓库下载 利用镜像创建并启动一个容器 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去 从地址池配置一个ip地址给容器 执行用户指定的应用程序 执行完毕后容器被终止 后台运行 很多时间,需要让Docker在后台运行而不是直接把执行命令的结果输出在当前宿主机下。此时,可以通过添加-d参数来实现。 如果不使用-d参数运行容器,比如docker run hello-world会把日志打印在控制台。如果使用-d参数运行容器,比如docker run -d hello-world不会输出日志,只会打印容器id(输出结果可以用docker logs查看); 注:容器是否会长久运行,是和docker run指定的命令有关,和-d参数无关。 停止运行的容器 可以使用docker container stop来终止一个运行中的容器。终止状态的容器可以用docker container ls -a 命令看到。处于终止状态的容器,可以通过docker container start命令来重新启动。此处,docker container restart命令会将一个运行态的容器终止,处于再重新启动它。 进入容器 在使用-d参数时,容器启动后进入后台,某些时候需要进入容器进行操作,使用docker exec命令可以进入到运行中。 exec命令 -i -t参数 docker exec后边可以跟多个参数,这是主要说明 -i -t参数。只用-i参数时,由于没有分配伪终端,界面没有我们熟悉的Linux命令提示符,但命令执行结果仍然可以返回。当-i -t参数一起使用时,则可以看到我们熟悉的Linux命令提示符。 docker exec -it 容器id /bin/bash 导出和导入容器 导出容器 如果要导出本地某个容器,可以使用docker export命令。 docker export 容器ID>导出文件名.tar 导入容器 可以使用docker import从容器快照文件中再导入为镜像 cat 导出文件名.tar|docker import - 镜像用户/镜像名:镜像版本 此外,也可以通过指定URL或者某个目录来导入 docker import http://study.163.com/image.tgz example/imagerepo 删除容器 删除容器 可以使用docker container rm来删除一个处于终止状态的容器 docker container rm ubuntu:16:04 如果要删除一个运行中的容器,可以添加-f参数。Docker会发送SIGKILL信号给容器。 清楚所有处于终止状态的容器 用docker container ls -a 命令可以查看所有已经创建的包括终止状态的容器,如果数量太多要一个个删除可以会很麻烦,用下面的命令可以清理掉所有处于终止状态的容器。 docker container prune

优秀的个人博客,低调大师

Docker入门基础之镜像使用

当运行容器时,使用的镜像如果在本地中不存在,docker 就会自动从 docker 镜像仓库中下载,默认是从 Docker Hub 公共镜像源下载。 下面我们来学习: 1、管理和使用本地 Docker 主机镜像 2、创建镜像 列出镜像列表我们可以使用 docker images 来列出存在于宿主机上的镜像。 root@ubuntu:~# docker images REPOSITORY TAG IMAGE ID CREATED SIZE alpine latest 055936d39205 3 weeks ago 5.53MB mysql 5.7 7faa3c53e6d6 3 weeks ago 373MB ubuntu 15.04 d1b55fd07600 3 years ago 131MB ubuntu 16.04 2a697363a870 2 weeks ago 119MB 各个选项说明: REPOSITORY:表示镜像的仓库源 TAG:镜像的标签 IMAGE ID:镜像ID CREATED:镜像创建时间 SIZE:镜像大小 同一仓库源可以有多个 TAG,代表这个仓库源的不同个版本,如ubuntu仓库源里,有16.04、15.04等多个不同的版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。 以相应的镜像启动容器我们如果要使用版本为16.04的ubuntu系统镜像来运行容器时,命令如下: root@ubuntu:~# docker run -it ubuntu:16.04 sh 如果要使用版本为15.04的ubuntu系统镜像,则命令如下: root@ubuntu:~# docker run -it ubuntu:15.04 sh 各个参数解析: docker: Docker 的二进制执行文件。 run: 与前面的 docker 组合来运行一个容器。 -it: 其实是两个参数组成, -i 和 -t,-i:允许你对容器内的标准输入 (STDIN) 进行交互。-t:在新容器内指定一个伪终端或终端。 ubuntu:15.04指定要运行的镜像,Docker首先从本地主机上查找镜像是否存在,如果不存在,Docker 就会从镜像仓库 Docker Hub 下载公共镜像。 sh: 执行命令。 获取一个新镜像当我们在宿主机上使用一个不存在的镜像时 Docker 就会自动下载这个镜像。如果我们想预先下载这个镜像,我们可以使用 docker pull 命令来下载它。 root@ubuntu:~# docker pull ubuntu:18.04 18.04: Pulling from library/ubuntu 6abc03819f3e: Pull complete 05731e63f211: Pull complete 0bd67c50d6be: Pull complete Digest: sha256:f08638ec7ddc90065187e7eabdfac3c96e5ff0f6b2f1762cf31a4f49b53000a5 Status: Downloaded newer image for ubuntu:18.04 下载完成后,我们可以直接使用这个镜像来运行容器。 查找镜像 我们可以从 Docker Hub 网站来搜索镜像,Docker Hub 网址为: https://hub.docker.com/我们也可以使用 docker search 命令来搜索镜像。比如我们需要一个httpd的镜像来作为我们的web服务。我们可以通过 docker search 命令搜索 httpd 来寻找适合我们的镜像。 NAME: 镜像仓库源的名称DESCRIPTION: 镜像的描述OFFICIAL: 是否docker官方发布 拉取httpd镜像我们决定使用上图中的httpd 官方版本的镜像,使用命令 docker pull 来下载镜像。 root@ubuntu:~# docker pull httpd Using default tag: latest latest: Pulling from library/httpd 743f2d6c1f65: Already exists c92eb69846a6: Pull complete 2211b052800a: Pull complete aed180197314: Pull complete 7c472a4980a7: Pull complete Digest: sha256:a35ad614c1ffc6fe931f12dc42b682edbdcc62cf78d8edc41499dd90ef0f8003 Status: Downloaded newer image for httpd:latest 下载完成后,我们就可以使用这个镜像了。 创建镜像当我们从docker镜像仓库中下载的镜像不能满足我们的需求时,我们可以通过以下两种方式对镜像进行更改。 1.从已经创建的容器中更新镜像,并且提交这个镜像 2.使用 Dockerfile 指令来创建一个新的镜像 更新镜像更新镜像之前,我们需要使用镜像来创建一个容器。 root@ubuntu:~# docker run -it ubuntu:16.04 sh 在运行的容器内使用 apt-get update 命令进行更新。 # apt-get update Get:1 http://archive.ubuntu.com/ubuntu xenial InRelease [247 kB] Get:2 http://security.ubuntu.com/ubuntu xenial-security InRelease [109 kB] Get:3 http://archive.ubuntu.com/ubuntu xenial-updates InRelease [109 kB] Get:4 http://archive.ubuntu.com/ubuntu xenial-backports InRelease [107 kB] Get:5 http://archive.ubuntu.com/ubuntu xenial/main amd64 Packages [1558 kB] Get:6 http://security.ubuntu.com/ubuntu xenial-security/main amd64 Packages [844 kB] Get:7 http://archive.ubuntu.com/ubuntu xenial/restricted amd64 Packages [14.1 kB] Get:8 http://archive.ubuntu.com/ubuntu xenial/universe amd64 Packages [9827 kB] Get:9 http://archive.ubuntu.com/ubuntu xenial/multiverse amd64 Packages [176 kB] Get:10 http://archive.ubuntu.com/ubuntu xenial-updates/main amd64 Packages [1237 kB] Get:11 http://security.ubuntu.com/ubuntu xenial-security/restricted amd64 Packages [12.7 kB] Get:12 http://security.ubuntu.com/ubuntu xenial-security/universe amd64 Packages [556 kB] Get:13 http://archive.ubuntu.com/ubuntu xenial-updates/restricted amd64 Packages [13.1 kB] Get:14 http://archive.ubuntu.com/ubuntu xenial-updates/universe amd64 Packages [967 kB] Get:15 http://archive.ubuntu.com/ubuntu xenial-updates/multiverse amd64 Packages [19.1 kB] Get:16 http://archive.ubuntu.com/ubuntu xenial-backports/main amd64 Packages [7942 B] Get:17 http://archive.ubuntu.com/ubuntu xenial-backports/universe amd64 Packages [8532 B] Get:18 http://security.ubuntu.com/ubuntu xenial-security/multiverse amd64 Packages [6113 B] Fetched 15.8 MB in 8s (1933 kB/s) Reading package lists... Done 在完成操作之后,输入 exit命令来退出这个容器。 通过 docker ps -a 查看所有容器: root@ubuntu:~# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 12847d9f5071 ubuntu:16.04 "sh" 2 minutes ago Exited (0) 43 seconds ago peaceful_edison 3cec6f5e47c0 httpd "httpd-foreground" 5 minutes ago Exited (0) 5 minutes ago vigilant_heisenberg 此时ID为12847d9f5071的容器,是按我们的需求更改的容器。我们可以通过命令docker commit来提交容器副本。 root@ubuntu:~# docker commit -m="has update" -a="yeqing112" 12847d9f5071 yeqing112/ubuntu:v2 sha256:5cce1167ee4c083ff9b87e61a58081805e76d015a12a4811bd152263aa013860 各个参数说明: -m: 提交的描述信息。 -a: 指定镜像作者。 12847d9f5071: 容器ID。 yeqing112/ubuntu:v2: 指定要创建的目标镜像名。 我们可以使用 docker images 命令来查看我们的新镜像 yeqing112/ubuntu:v2: root@ubuntu:~# docker images REPOSITORY TAG IMAGE ID CREATED SIZE yeqing112/ubuntu v2 5cce1167ee4c 2 minutes ago 144MB ubuntu 16.04 2a697363a870 2 weeks ago 119MB 从上面的信息中可以看到我们更新过的镜像,文件体积明显比之前大了一些。 构建镜像除了上面更新镜像的方法,我们还可以使用命令 docker build , 从零开始来构建一个新的镜像。为此,我们需要创建一个 Dockerfile 文件,其中包含一组指令来告诉 Docker 如何构建我们的镜像。 root@ubuntu:~# cat Dockerfile FROM ubuntu:16.04 MAINTAINER Fisher "service@urlos.com" RUN apt-get update EXPOSE 22 EXPOSE 80 CMD /bin/bash 每一个指令都会在镜像上创建一个新的层,每一个指令的前缀都必须是大写的。 第一条FROM,指定使用哪个镜像源 RUN 指令告诉docker 在镜像内执行命令,安装了什么 这里我们还是一样,执行一个 apt-get update 更新命令 然后,我们使用 Dockerfile 文件,通过 docker build -t yeqing112/ubuntu:v3 . 命令来构建一个新镜像。 root@ubuntu:~# root@ubuntu:/home# docker build -t yeqing112/ubuntu:v3 . Sending build context to Docker daemon 422.4kB Step 1/6 : FROM ubuntu:16.04 ---> 2a697363a870 Step 2/6 : MAINTAINER Fisher "service@urlos.com" ---> Running in 92229e7a091a Removing intermediate container 92229e7a091a ---> 9a89f4debc7d Step 3/6 : RUN apt-get update ---> Running in d709ef335784 Get:1 http://archive.ubuntu.com/ubuntu xenial InRelease [247 kB] Get:2 http://security.ubuntu.com/ubuntu xenial-security InRelease [109 kB] Get:3 http://archive.ubuntu.com/ubuntu xenial-updates InRelease [109 kB] Get:4 http://archive.ubuntu.com/ubuntu xenial-backports InRelease [107 kB] Get:5 http://security.ubuntu.com/ubuntu xenial-security/main amd64 Packages [844 kB] Get:6 http://archive.ubuntu.com/ubuntu xenial/main amd64 Packages [1558 kB] Get:7 http://archive.ubuntu.com/ubuntu xenial/restricted amd64 Packages [14.1 kB] Get:8 http://archive.ubuntu.com/ubuntu xenial/universe amd64 Packages [9827 kB] Get:9 http://security.ubuntu.com/ubuntu xenial-security/restricted amd64 Packages [12.7 kB] Get:10 http://security.ubuntu.com/ubuntu xenial-security/universe amd64 Packages [556 kB] Get:11 http://archive.ubuntu.com/ubuntu xenial/multiverse amd64 Packages [176 kB] Get:12 http://archive.ubuntu.com/ubuntu xenial-updates/main amd64 Packages [1237 kB] Get:13 http://archive.ubuntu.com/ubuntu xenial-updates/restricted amd64 Packages [13.1 kB] Get:14 http://archive.ubuntu.com/ubuntu xenial-updates/universe amd64 Packages [967 kB] Get:15 http://archive.ubuntu.com/ubuntu xenial-updates/multiverse amd64 Packages [19.1 kB] Get:16 http://archive.ubuntu.com/ubuntu xenial-backports/main amd64 Packages [7942 B] Get:17 http://archive.ubuntu.com/ubuntu xenial-backports/universe amd64 Packages [8532 B] Get:18 http://security.ubuntu.com/ubuntu xenial-security/multiverse amd64 Packages [6113 B] Fetched 15.8 MB in 5s (3051 kB/s) Reading package lists... Removing intermediate container d709ef335784 ---> 540751496556 Step 4/6 : EXPOSE 22 ---> Running in 9ae528bc083f Removing intermediate container 9ae528bc083f ---> cfccc621a52d Step 5/6 : EXPOSE 80 ---> Running in efd88e9349c1 Removing intermediate container efd88e9349c1 ---> 428cb5221a06 Step 6/6 : CMD /bin/bash ---> Running in 2bc08b664f97 Removing intermediate container 2bc08b664f97 ---> 9c55ea9b9ee8 Successfully built 9c55ea9b9ee8 Successfully tagged yeqing112/ubuntu:v3 参数说明: -t:指定要创建的目标镜像名 .:Dockerfile 文件所在目录,可以指定Dockerfile 的绝对路径 构建成功后,使用 docker images 查看镜像: root@ubuntu:~# docker images REPOSITORY TAG IMAGE ID CREATED SIZE yeqing112/ubuntu v3 9c55ea9b9ee8 9 seconds ago 144MB yeqing112/ubuntu v2 5cce1167ee4c 16 minutes ago 144MB ubuntu 16.04 2a697363a870 2 weeks ago 119MB 由上面的信息看出,新的镜像v3与v2文件体积是一样的,两个镜像都只是执行了apt-get update 设置镜像标签我们可以使用 docker tag 命令,为镜像添加一个新的标签。 root@ubuntu:/home# docker tag 9c55ea9b9ee8 yeqing112/ubuntu:v3-1 docker tag 镜像ID,这里是 9c55ea9b9ee8,用户名称、镜像源名(repository name)和新的标签名(tag)。 使用 docker images 命令可以看到,ID为9c55ea9b9ee8的镜像多了一个v3-1的标签。 root@ubuntu:/home# docker images REPOSITORY TAG IMAGE ID CREATED SIZE yeqing112/ubuntu v3 9c55ea9b9ee8 21 minutes ago 144MB yeqing112/ubuntu v3-1 9c55ea9b9ee8 21 minutes ago 144MB yeqing112/ubuntu v2 5cce1167ee4c 38 minutes ago 144MB ubuntu 16.04 2a697363a870 2 weeks ago 119MB

优秀的个人博客,低调大师

Docker入门基础之应用实战

当我们掌握了Docker镜像和容器的基本用法后,我们现在能做些什么事情呢?现在我们就来看看使用Docker容器如何安装常见的软件,然后运行一个动态网站。 下面我们来学习: 1、安装Nginx 2、安装PHP 3、使用MySQL服务 4、运行wordpress博客 安装Nginx运行一个Alpine的容器,选择Alpine作为系统基础镜像是因为Alpine轻巧的体积,基础镜像只有5.53MB,相比ubuntu镜像的88.9MB要小十几倍。 root@ubuntu:~# docker run -it -p 8080:80 alpine sh 安装nginx apk add nginx 修改nginx配置 vi /etc/nginx/conf.d/default.conf default.conf内容如下: server { listen 80 default_server; ​ root /home/www; index index.php index.html; } 创建Hello World mkdir /home/www && echo "Hello World" > /home/www/index.html 创建/run/nginx目录 mkdir /run/nginx 启动nginx nginx 在浏览器中访问 http://192.168.43.122:8080 nginx安装成功,WEB服务访问正常! 安装PHP现在我们来安装PHP,方法还是一样,使用 apk add 命令来安装php7,php-fpm以及相关扩展。 apk add --no-cache php7 php7-fpm php7-ftp php7-pdo php7-mysqli php7-simplexml php7-xmlwriter php7-zlib php7-imagick php7-memcached php7-sockets php7-mcrypt php7-zip php7-pgsql php7-pdo_odbc php7-odbc php7-curl php7-iconv php7-xml php7-json php7-gd php7-session php7-opcache php7-pdo_sqlite php7-mbstring php7-common php7-pdo_mysql 以上顺带安装了很多php扩展,可根据实际需求增减。 现在启动php-fpm7 php-fpm7 修改nginx配置,添加php支持 vi /etc/nginx/conf.d/default.conf 内容如下 server { listen 80 default_server; root /home/www; index index.php index.html; location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME /home/www$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } } 在网站目录中创建phpinfo.php echo "<?php phpinfo(); ?>" > /home/www/phpinfo.php 重启nginx nginx -s reload 在浏览器中访问 http://192.168.43.122:8080/phpinfo.php PHP安装成功,WEB服务访问正常! 使用MySQL服务我们不在Alpine里面安装MySQL,为了使用效率,这里我们直接使用官方镜像即可,新开一个ssh终端连接宿主机,在home目录下新建database目录 mkdir /home/database 使用官方mysql5.7镜像运行一个容器,root密码设置为123456,映射3306端口,并将宿主机/home/database目录挂载到容器/var/lib/mysql目录 docker run -dit -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -v /home/database:/var/lib/mysql mysql:5.7 docker ps查看容器 上图中看到,我们现在运行了2个容器,1个是安装了nginx和php的Alpine容器,1个是mysql5.7的容器 进入mysql容器 docker exec -it c8c85af64822 sh 登录并创建wordpress数据库 #用root用户登录 mysql -u root -p #创建wordpress数据库 mysql> CREATE DATABASE wordpress; 运行wordpress博客php网站环境和mysql数据库都准备好了,现在我们回到Alpine的ssh终端上,在容器内下载一个wordpress网站程序。 #进入网站目录 cd /home/www/ #下载wordpress wget https://wordpress.org/latest.tar.gz #解压 tar zxvf latest.tar.gz #将wordpress目录下的文件复制到www目录下 cp -ri /home/www/wordpress/* /home/www/ #设置777权限 chmod -R 777 /home/www/ 在浏览器中访问 http://192.168.43.122:8080,可以看到wordpres页面 填写数据库信息 安装完成,wordpress正常使用!

优秀的个人博客,低调大师

Python3入门(八)模块

模块是一个包含所有你定义的函数和变量的文件,其后缀名是.py。模块可以被别的程序引入,以使用该模块中的函数等功能。这也是使用python 标准库的方法。 一、import语句 使用 Python 源文件,只需在另一个源文件里执行 import 语句,语法如下import module1[, module2[,... moduleN]当解释器遇到 import 语句,如果模块在当前的搜索路径就会被导入。搜索路径是一个解释器会先进行搜索的所有目录的列表,以下为一个demo test.py文件,用于其他文件导入 def test(): print("hello import") test2.py文件,引入test.py import test test.test() 输出:hello import一个模块只会被导入一次,不管你执行了多少次

优秀的个人博客,低调大师

Python3入门(七)函数

函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数 一、定义一个函数 定义一个由自己想要功能的函数,以下是简单的规则 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 () 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明 函数内容以冒号起始,并且缩进 return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None格式如下: def 函数名(参数列表): 函数体 实例: def hello(): print("hello def")

优秀的个人博客,低调大师

阿里云入门搭建小细节

前言实习生涯还在继续,这两天倒腾了一下阿里云。下面来分享一下。 云服务器我觉得就是一台电脑,只不过你可以用,但是不能摸到,拿来挂QQ,挂个人网站,等等都行。 所以接下来开始入云端吧。 一、云服务器ECS购买 首先是买服务器,由于我还是学生,所以可以在阿里云便宜的买到一个服务器(配置比较低)。 名词解释:预装环境: 就是你买的服务器给你装什么系统(谨慎选择貌似后期无法更换), 图中,CentOS,Ubuntu 都是Linux系统,下面两个都是windows专门的服务器系统。 没玩过Linux的可以选下面两个试试水。 地域: 顾名思义吧,就是你的机子实际所在的地方。主要考虑的是,服务器目标用户所在地和 服务器直接的通信问题。一般来说越近越好。地域对应关系见下图↓↓↓ 还有就是服务器性能问题,上图的配置其实也够个人用的了,还有上图的网络速度其实 指的是服务器的上行速度,也就是外网的下行速度,实际服务器的下行速度还是很快的。 我选的是,Windows的服务器。 二、上云买好服务器以后就可以进入管理界面准备上云了。 首先是界面: 云服务器ECS-->实例 就可以看到你刚刚买的服务器了。你可以给它改名重启之类的。当然你最关心的应该是连接的问题。 名词解释:IP地址: 分为公网和内网(私有),公网就是可以在外面连接进来的IP地址,这个很重要,记下来。别人要访问你的 云电脑都靠他。 网络类型: 我也不懂,专业的应该 更好。 操作: 里面有很多按钮, 管理:就是进入实例的管理页面 远程连接:官方的远程连接页面 升降配:顾名思义花钱的地方 更多:里面有很多选项碰到在解释吧。目前就一个安全组很有用, 安全组: 管理进出服务器的流量的IP地址。 出方向,默认服务器可以到任何IP, 入方向,规定什么IP可以访问本地什么端口。 要远程连接 需开放 3389端口,接下来看看怎么开放3389接口 进入安全组后点配置规则 我们要配置的是入方向的端口和IP。 要添加端口点右上角 添加安全组规则 这样配置就行了。0.0.0.0/0 就是所有IP都能访问该端口。 (有3389的老哥就不用配置了,不过需要学会配置,后面还有别的端口需要开放) 然后需要吧 配置好的 安全组 对应到 服务器(实例) 点击加入对应的安全组就行了。 好了,前面解释的有点冗长,重点 是连接部分,首先点击 操作里面的远程连接 进入一个页面,第一次会告诉你连接密码。暂时先记住(后面可以修改), 输入密码-->发送远程命令 然后就是下面这个界面,这个初始密码我也不知道, 而且也没告诉你,所以只能自己去改了。 修改登录密码: 前面提到的 管理-->实例详情-->更多-->重置密码 改好之后就可以去登陆了。 三、用云这个系统登录以后还需要配置一些东西。 登录进去以后,左下角点一下进入服务器管理器,右边按照我红色标记设置。 接下来说一些实际需要用到的东西.。 Windows系统自带的远程连接:这是以后管理服务器最常用的手段。 首先,win+R 调出运行界面输入mstsc,会出现下面窗口 需要输入的就是 前面 服务器界面的 公网IP 用户名是administrator,密码是 远程连接密码(六位的)。不是登录密码 PS:一些其他的设置在左下角的显示选项里面,可以设置服务器和当前电脑文件互传之类的, 可以自行百度。 安全组:在实际开发的时候还需要开放一些 别的端口给外网。 下面稍微罗列一些 常用的: 80端口为HTTP网页访问的端口3389端口为远程桌面连接的端口21/tcp FTP 文件传输协议 22/tcp SSH 安全登录、文件传送(SCP)和端口重定向 443HTTPS 3306 Mysql(远程连接数据库用) 8080 Tomcat (做网站用) 当然后面Mysql和Tomcat的端口可以自己指定,3306和8080只是常用的端口。 最后这几天玩了一下阿里云服务器,学到了不少,来分享了一下,有些乱,还有些东西没写上来, 剩下的就是远程连接你的服务器,玩它就行了。了解更多产品详情可点击加关注

优秀的个人博客,低调大师

30 分钟快速入门 Docker 教程

原文地址:梁桂钊的博客 博客地址:http://blog.720ui.com 欢迎关注公众号:「服务端思维」。一群同频者,一起成长,一起精进,打破认知的局限性。 一、欢迎来到 Docker 世界 1. Docker 与虚拟化 在没有 Docker 的时代,我们会使用硬件虚拟化(虚拟机)以提供隔离。这里,虚拟机通过在操作系统上建立了一个中间虚拟软件层 Hypervisor ,并利用物理机器的资源虚拟出多个虚拟硬件环境来共享宿主机的资源,其中的应用运行在虚拟机内核上。但是,虚拟机对硬件的利用率存在瓶颈,因为虚拟机很难根据当前业务量动态调整其占用的硬件资源,因此容器化技术得以流行。其中,Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上。 Docker 容器不使

优秀的个人博客,低调大师

Elasticsearch通关教程(一): 基础入门

简介 Elasticsearch是一个高度可扩展的、开源的、基于 Lucene 的全文搜索和分析引擎。它允许您快速,近实时地存储,搜索和分析大量数据,并支持多租户。 Elasticsearch也使用Java开发并使用 Lucene 作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的 RESTful API 来隐藏 Lucene 的复杂性,从而让全文搜索变得简单。 不过,Elasticsearch 不仅仅是 Lucene 和全文搜索,我们还能这样去描述它: 分布式的实时文件存储,每个字段都被索引并可被搜索 分布式的实时分析搜索引擎 可以扩展到上百台服务器,处理PB级结构化或非结构化数据 而且,所有的这些功能被集成到一个服务里面,你的应用可以通过简单的RESTful API、各种语言的客户端甚至命令行与之交互。 版本选择 在决定使用 Elasticsearch 的时候首先要考虑的是版本问题,Elasticsearch 目前有三个常用的稳定的主版本:2.x,5.x,6.x(排除 0.x 和 1.x)。 Elasticsearch 可以在这里查看所有历史版本,博主写这篇博文的时候最新的是 Elasticsearch 6.4.2。你可能会发现没有 3.x 和 4.x,ES 从 2.4.6 直接跳到了 5.0.0。这是为什么? 其实是为了ELK(ElasticSearch, logstash, kibana)技术栈的版本统一,免的给用户带来混乱。 我们知道 elasticsearch,kibana,logstash 都是 Elastic Stack 成员, 而且很多时候都是配合使用,那么为了协同开发,避免造成版本困惑,所以需要统一版本,至少保持在一个主版本号下。 在 Elasticsearch 是 2.x (2.x 的最后一版 2.4.6 的发布时间是 July 25, 2017) 的情况下,kibana 已经是 4.x(Kibana 4.6.5 的发布时间是 July 25, 2017),那么在 kibana 的下一主版本肯定是 5.x 了,所以 Elasticsearch 直接将自己的主版本发布为 5.0.0 了。统一之后,我们选版本就不会犹豫困惑了,我们选定 elasticsearch 的版本后再选择相同版本的 kibana 就行了,不用担忧版本不兼容的问题。 版本选择可以从以下几个方面考虑: 版本问题 2.x 版本较老,无法体验新功能,且性能不如 5.x。 6.x 版本有点新,网上资料相对比较少(开发时间充足的可以研究)。 数据迁移 2.x 版本数据可以直接迁移到 5.x; 5.X 版本的数据可以直接迁移到 6.x; 但是 2.x 版本数据无法直接迁移到 6.x。 周边工具 2.x 版本周边工具版本比较混乱;Kibana 等工具的对应版本需要自己查,不好匹配。 5.x 之后 Kibana 等工具的主版本号进行了统一。 Sql 语法支持 2.x,5.x,6.x 都可以安装 Elasticsearch-sql 插件,使用熟悉的SQL语法查询 Elasticsearch。 6.3.0 以后内置支持 SQL 模块,这个 SQL 模块是属于 X-Pack 的一部分。 通过以上的版本号了解之后,综合考虑,我起始选择了 elasticsearch 6.4.0版本,其实主要是因为它新,kibana 也选择了 kibana 6.4.0。但是等本地开发完成准备部署的时候,运维通知切换到5.6.0,因为公司其他部门的是5.6.0,方便统一维护,还好 API 变化不大。 环境搭建 安装 Elasticsearch Elasticsearch5.0之后的版本至少需要Java 8。可通过如下命令检查Java版本,然后根据需要进行相应的安装/升级。 java -version echo $ JAVA_HOME 你可以从 elastic.co/download 下载你需要的版本的Elasticsearch,解压之后即可使用。 如果是集群形式的,可在 ...\elasticsearch-5.6.0\config\elasticsearch.yml中配置一些你的集群信息: cluster.name: my-application # 集群名称 path.data: /path/to/data # ES数据存储路径 path.logs: /path/to/logs # ES日志存储路径 node.name: node-1 # 当前节点的名称 network.host: 192.168.0.1 # 配置当前结点绑定的IP地址,可设置为0.0.0.0 http.port: 9200 # 设置对外服务的HTTP端口,默认为9200 运行 Elasticsearch elasticsearch 准备好之后,在安装目录中执行以下命令可以启动运行: Linux ./bin/elasticsearch Windows D:\...\elasticsearch-6.4.0\bin\elasticsearch.bat 运行成功之后(启动日志里面会有.. started标志),浏览器访问http://localhost:9200/?pretty,你能看到类似以下返回信息(各版本稍微不同): { "name" : "AGXQ3qy", "cluster_name" : "elasticsearch", "cluster_uuid" : "mg9t4Yi2TRud1JNwRY0bPA", "version" : { "number" : "6.4.0", "build_flavor" : "default", "build_type" : "zip", "build_hash" : "595516e", "build_date" : "2018-08-17T23:18:47.308994Z", "build_snapshot" : false, "lucene_version" : "7.4.0", "minimum_wire_compatibility_version" : "5.6.0", "minimum_index_compatibility_version" : "5.0.0" }, "tagline" : "You Know, for Search" } 这说明你的 Elasticsearch 集群已经启动成功并且正常运行,接下来我们可以开始使用了。 可视化 web 界面 由于 Elasticsearch 的交互方式是 Rest 形式的,这种不是很直观方便,我们先安装图视化界面,方便我们操作。可选择的目前主要有 elasticsearch-head 和 kibana。 elasticsearch-head elasticsearch-head 是一个用于浏览和与 elasticsearch 集群交互的Web前端。elasticsearch-head 是 elasticsearch 集群管理、数据可视化、增删查改、查询语句可视化工具。elasticsearch head 是托管的,可以在 github 下载或 fork。 有两种运行和安装elasticsearch-head的方法: 作为ElasticSearch的插件运行(这是首选方法) elasticsearch/bin/elasticsearch-plugin -install mobz/elasticsearch-head。 open http://localhost:9200/_plugin/head/。 注意: 插件的安装方法,5.0之前为 plugin -install …,而在 5.0 以后为 elasticsearch-plugin -install …。 作为独立的webapp运行 git clone git://github.com/mobz/elasticsearch-head.git。 在浏览器中打开 index.html。现代浏览器需要使用 es-head。 默认情况下,es-head 将尝试连接到http:// localhost:9200 /的集群节点。在连接框中输入不同的节点地址,如果需要,单击“连接”。 成功后的界面如下,可以看到集群的状态信息: 由于 Head 安装起来比较麻烦( 需要安装 node.js ),网上资料也很多,所以我就不详细说了,更多信息可参考:elasticsearch-head kibana Kibana 和 elasticsearch 同属于 elastic 公司。 Kibana是一个开源分析和可视化平台,旨在与Elasticsearch协同工作。您使用Kibana搜索,查看和与存储在 Elasticsearch 索引中的数据进行交互。您可以轻松地执行高级数据分析,并在各种图表,表格和地图中可视化您的数据。 Kibana 使您可以轻松理解大量数据。其简单的基于浏览器的界面使您能够快速创建和共享动态仪表板,实时显示 Elasticsearch 查询的更改。 设置 Kibana 非常容易。您可以安装 Kibana 并在几分钟内开始探索您的 Elasticsearch 索引 - 无需代码,无需额外的基础架构。 同样可在 kibana 选择需要的对应版本(与 elasticsearch 版本对应),然后下载解压即可使用,具体步骤如下: 下载并解压缩 Kibana。 在编辑器中打开 config / kibana.yml。 设置 elasticsearch.url 为您的Elasticsearch实例,如本地:elasticsearch.url: "http://localhost:9200"。 运行 bin/kibana(或binkibana.bat在Windows上)。 浏览器输入 http:// localhost:5601。 如果运行成功,但是无法访问,可以关闭防火墙再试试。 基本概念 一切准备就绪,我们正式操作之前,先来了解一些 ES 的核心基本概念,从一开始就理解这些概念将极大地帮助简化学习过程。 Elasticsearch是一个近乎实时(NRT)的搜索平台。这意味着从索引文档到可搜索文档的时间有一点延迟(通常是一秒)。通常有集群,节点,分片,副本等概念。 集群(Cluster) 集群(cluster)是一组具有相同cluster.name的节点集合,他们协同工作,共享数据并提供故障转移和扩展功能,当然一个节点也可以组成一个集群。 集群由唯一名称标识,默认情况下为“elasticsearch”。此名称很重要,因为如果节点设置为按名称加入集群的话,则该节点只能是集群的一部分。 确保不同的环境中使用不同的集群名称,否则最终会导致节点加入错误的集群。 【集群健康状态】 集群状态通过 绿,黄,红 来标识 绿色 - 一切都很好(集群功能齐全)。 黄色 - 所有数据均可用,但尚未分配一些副本(集群功能齐全)。 红色 - 某些数据由于某种原因不可用(集群部分功能)。 注意:当群集为红色时,它将继续提供来自可用分片的搜索请求,但您可能需要尽快修复它,因为存在未分配的分片。 要检查群集运行状况,我们可以在 Kibana 控制台中运行以下命令GET /_cluster/health,得到如下信息: { "cluster_name": "elasticsearch", "status": "yellow", "timed_out": false, "number_of_nodes": 1, "number_of_data_nodes": 1, "active_primary_shards": 28, "active_shards": 28, "relocating_shards": 0, "initializing_shards": 0, "unassigned_shards": 5, "delayed_unassigned_shards": 0, "number_of_pending_tasks": 0, "number_of_in_flight_fetch": 0, "task_max_waiting_in_queue_millis": 0, "active_shards_percent_as_number": 84.84848484848484 } 节点(Node) 节点,一个运行的 ES 实例就是一个节点,节点存储数据并参与集群的索引和搜索功能。 就像集群一样,节点由名称标识,默认情况下,该名称是在启动时分配给节点的随机通用唯一标识符(UUID)。如果不需要默认值,可以定义所需的任何节点名称。此名称对于管理目的非常重要,您可以在其中识别网络中哪些服务器与 Elasticsearch 集群中的哪些节点相对应。 可以将节点配置为按集群名称加入特定集群。默认情况下,每个节点都设置为加入一个名为 cluster 的 elasticsearch 集群,这意味着如果您在网络上启动了许多节点并且假设它们可以相互发现 - 它们将自动形成并加入一个名为 elasticsearch 的集群。 索引(Index) 索引是具有某些类似特征的文档集合。例如,您可以拥有店铺数据的索引,商品的一个索引以及订单数据的一个索引。 索引由名称标识(必须全部小写),此名称用于在对其中的文档执行索引,搜索,更新和删除操作时引用索引。 类型(Type) 类型,曾经是索引的逻辑类别/分区,允许您在同一索引中存储不同类型的文档,例如,一种类型用于用户,另一种类型用于博客帖子。 在 6.0.0 中弃用,以后将不再可能在索引中创建多个类型,并且将在更高版本中删除类型的整个概念。 文档(Document) 文档是可以建立索引的基本信息单元。例如,您可以为单个客户提供文档,为单个产品提供一个文档,为单个订单提供一个文档。该文档以JSON(JavaScript Object Notation)表示,JSON是一种普遍存在的互联网数据交换格式。 在索引/类型中,您可以根据需要存储任意数量的文档。请注意,尽管文档实际上驻留在索引中,但实际上必须将文档编入索引/分配给索引中的类型。 分片(Shards) 索引可能存储大量可能超过单个节点的硬件限制的数据。例如,占用1TB磁盘空间的十亿个文档的单个索引可能不适合单个节点的磁盘,或者可能太慢而无法单独从单个节点提供搜索请求。 为了解决这个问题,Elasticsearch 提供了将索引细分为多个称为分片的功能。创建索引时,只需定义所需的分片数即可。每个分片本身都是一个功能齐全且独立的“索引”,可以托管在集群中的任何节点上。 设置分片的目的及原因主要是: 它允许您水平拆分/缩放内容量 它允许您跨分片(可能在多个节点上)分布和并行化操作,从而提高性能/吞吐量 分片的分布方式以及如何将其文档聚合回搜索请求的机制完全由 Elasticsearch 管理,对用户而言是透明的。 在可能随时发生故障的网络/云环境中,分片非常有用,建议使用故障转移机制,以防分片/节点以某种方式脱机或因任何原因消失。为此,Elasticsearch 允许您将索引的分片的一个或多个副本制作成所谓的副本分片或简称副本。 副本(Replicasedit) 副本,是对分片的复制。目的是为了当分片/节点发生故障时提供高可用性,它允许您扩展搜索量/吞吐量,因为可以在所有副本上并行执行搜索。 总而言之,每个索引可以拆分为多个分片。索引也可以复制为零次(表示没有副本)或更多次。复制之后,每个索引将具有主分片(从原始分片复制而来的)和复制分片(主分片的副本)。 可以在创建索引时为每个索引定义分片和副本的数量。创建索引后,您也可以随时动态更改副本数。您可以使用_shrink 和 _splitAPI 更改现有索引的分片数,但这不是一项轻松的任务,所以预先计划正确数量的分片是最佳方法。 默认情况下,Elasticsearch 中的每个索引都分配了5个主分片和1个副本,这意味着如果集群中至少有两个节点,则索引将包含5个主分片和另外5个副本分片(1个完整副本),总计为每个索引10个分片。 小结 我们假设有一个集群由三个节点组成(Node1 , Node2 , Node3)。 它有两个主分片(P0 , P1),每个主分片有两个副本分片(R0 , R1)。相同分片的副本不会放在同一节点,所以我们的集群看起来如下图所示 “有三个节点和一个索引的集群”。 类似于关系型数据库:数据库集群,假如有个用户表,我担心数据量过大,我新建了多个用户表(即 Shard),将用户信息数据切分成多份,然后根据某种规则分到这些用户表中,我又担心某个表会出现异常造成数据丢失,我又将每个表分别备份了一次(即 Replica )。 副本是乘法,越多越浪费,但也越保险。分片是除法,分片越多,单分片数据就越少也越分散。 另外,我们可以画一个对比图来类比传统关系型数据库: 关系型数据库 -> Databases(库) -> Tables(表) -> Rows(行) -> Columns(列)。 Elasticsearch -> Indeces(索引) -> Types(类型) -> Documents(文档) -> Fields(属性)。 Elasticsearch集群可以包含多个索引(indices)(数据库),每一个索引可以包含多个类型 (Types)(表),每一个类型包含多个文档(documents)(行),然后每个文档包含多个字段(Fields)(列)。 虽然这么类比,但是毕竟是两个差异化的产品,而且上面也说过在以后的版本中类型 (Types) 可能会被删除,所以一般我们创建索引都是一个种类对应一个索引。生鲜就创建商品的索引,生活用品就创建生活用品的索引,而不会说创建一个商品的索引,里面既包含生鲜的类型,又包含生活用品的类型。 而且你可能已经注意到索引(index)这个词在Elasticsearch中有着不同的含义,所以有必要在此做一下区分: 「索引」含义的区分 索引(名词) 如上文所述,一个索引(index)就像是传统关系数据库中的数据库,它是相关文档存储的地方,index的复数是 indices 或 indexes。 索引(动词) 「索引一个文档」表示把一个文档存储到索引(名词)里,以便它可以被检索或者查询。这很像SQL中的INSERT关键字,差别是,如果文档已经存在,新的文档将覆盖旧的文档。 倒排索引 传统数据库为特定列增加一个索引,例如B-Tree索引来加速检索。Elasticsearch和Lucene使用一种叫做倒排索引(inverted index)的数据结构来达到相同目的。 与Elasticsearch交互 目前与 elasticsearch 交互主要有两种方式:Client API 和 RESTful API。 Client API方式: Elasticsearch 为以下语言提供了官方客户端 --Groovy、JavaScript、.NET、 PHP、 Perl、 Python 和 Ruby--还有很多社区提供的客户端和插件,所有这些都可以在 Elasticsearch Clients 中找到。后面再开一篇来详细说明。 RESTful API with JSON over HTTP: 所有其他语言可以使用 RESTful API 通过端口 9200 和 Elasticsearch 进行通信,你可以用你最喜爱的 web 客户端访问 Elasticsearch 。事实上,正如你所看到的,你甚至可以使用 curl 命令来和 Elasticsearch 交互。 一个 Elasticsearch 请求和任何 HTTP 请求一样由若干相同的部件组成: curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>' 被 < > 标记的部件: 数据格式 在应用程序中对象很少只是一个简单的键和值的列表。通常,它们拥有更复杂的数据结构,可能包括日期、地理信息、其他对象或者数组等。 也许有一天你想把这些对象存储在数据库中。使用关系型数据库的行和列存储,这相当于是把一个表现力丰富的对象挤压到一个非常大的电子表格中:你必须将这个对象扁平化来适应表结构,通常一个字段对应一列,而且又不得不在每次查询时重新构造对象。 Elasticsearch 是面向文档的,意味着它存储整个对象或文档。Elasticsearch 不仅存储文档,而且 每个文档的内容可以被检索。在 Elasticsearch 中,你对文档进行索引、检索、排序和过滤而不是对行列数据。这是一种完全不同的思考数据的方式,也是 Elasticsearch 能支持复杂全文检索的原因。 Elasticsearch 使用 JavaScript Object Notation 或者 JSON 作为文档的序列化格式。JSON 序列化被大多数编程语言所支持,并且已经成为 NoSQL 领域的标准格式。 它简单、简洁、易于阅读。几乎所有的语言都有相应的模块可以将任意的数据结构或对象 转化成 JSON 格式,只是细节各不相同。 { "_index" : "megacorp", "_type" : "employee", "_id" : "1", "_version" : 1, "found" : true, "_source" : { "first_name" : "John", "last_name" : "Smith", "age" : 25, "about" : "I love to go rock climbing", "interests": [ "sports", "music" ] } } 索引的应用 一切准备就绪之后我们开始来使用起来,体验 ElasticSearch 的世界。首先,我们来查看我们的所有索引信息: GET _search { "query": { "match_all": {} } } 得到如下结果信息: { "took": 0, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": 1, "max_score": 1, "hits": [ { "_index": ".kibana", "_type": "config", "_id": "5.6.0", "_score": 1, "_source": { "buildNum": 15523 } } ] } } 可以发现,当前只有一个索引,是.kibana,当然这不是我们自己的,这是kibana的。 创建第一个简单索引 NBA的新的赛季又开始了,我相信大部分人有精彩比赛的时候还是会去关注的,我们创建一个 NBA 球队的索引,开始我们的学习之路,索引名称需是小写。 PUT nba { "settings":{ "number_of_shards": 3, "number_of_replicas": 1 }, "mappings":{ "nba":{ "properties":{ "name_cn":{ "type":"text" }, "name_en":{ "type":"text" }, "gymnasium":{ "type":"text" }, "topStar":{ "type":"text" }, "championship":{ "type":"integer" }, "date":{ "type":"date", "format":"yyyy-MM-dd HH:mm:ss|| yyy-MM-dd||epoch_millis" } } } } } 字段说明: 字段名称 字段说明 nba 索引 number_of_shards 分片数 number_of_replicas 副本数 name_cn 球队中文名 name_en 球队英文名 gymnasium 球馆名称 championship 总冠军次数 topStar 当家球星 date 加入NBA年份 如果格式书写正确,我们会得到如下返回信息,表示创建成功 { "acknowledged": true, "shards_acknowledged": true, "index": "nba" } 新增索引数据 索引创建完成之后,我们往索引中加入球队数据,1,2,3 是我们指定的 ID,如果不写 ES 会默认ID。 其实我们可以不创建上面的索引 mapping 直接推送数据,但是这样 ES 会根据数据信息自动为我们设定字段类型,这会造成索引信息不准确的风险。 PUT /nba/nba/1 { "name_en":"San Antonio Spurs SAS", "name_cn":"圣安东尼安马刺", "gymnasium":"AT&T中心球馆", "championship": 5, "topStar":"蒂姆·邓肯", "date":"1995-04-12" } PUT /nba/nba/2 { "name_en":"Los Angeles Lakers", "name_cn":"洛杉矶湖人", "gymnasium":"斯台普斯中心球馆", "championship": 16, "topStar":"科比·布莱恩特", "date":"1947-05-12" } PUT /nba/nba/3 { "name_en":"Golden State Warriors", "name_cn":"金州勇士队", "gymnasium":"甲骨文球馆", "championship": 6, "topStar":"斯蒂芬·库里", "date":"1949-06-13" } PUT /nba/nba/4 { "name_en":"Miami Heat", "name_cn":"迈阿密热火队", "gymnasium":"美国航空球场", "championship": 3, "topStar":"勒布朗·詹姆斯", "date":"1988-06-13" } PUT /nba/nba/5 { "name_en":"Cleveland Cavaliers", "name_cn":"克利夫兰骑士队", "gymnasium":"速贷球馆", "championship": 1, "topStar":"勒布朗·詹姆斯", "date":"1970-06-13" } 索引数据 PUT 成功,会返回如下信息 { "_index": "nba", "_type": "nba", "_id": "1", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": true } 查询索引数据 上面新增完数据之后,这时候我们再执行开始的 MATCH_ALL ,就会发现我们自己的索引信息也在查询的结果里面了,只是查询的结果是全部信息,其中包括索引、分片和副本的信息,内容比较多。我们可单独查询自己需要的索引信息。 Elasticsearch 提供丰富且灵活的查询语言叫做 DSL 查询 (Query DSL) ,它允许你构建更加复杂、强大的搜索。 1.匹配查询 match,match_all 我们尝试一个最简单的搜索全部员工的请求: # 查询全部球队的信息 GET /nba/nba/_search { "query": { "match_all": {} } } 得到的查询结果如下 { "took": 4, "timed_out": false, "_shards": { "total": 3, "successful": 3, "skipped": 0, "failed": 0 }, "hits": { "total": 3, "max_score": 1, "hits": [ { "_index": "nba", "_type": "nba", "_id": "2", "_score": 1, "_source": { "name_en": "Los Angeles Lakers", "name_cn": "洛杉矶湖人", "gymnasium": "斯台普斯中心球馆", "championship": 16, "topStar": "科比·布莱恩特", "date": "1947-05-12" } }, { "_index": "nba", "_type": "nba", "_id": "1", "_score": 1, "_source": { "name_en": "San Antonio Spurs SAS", "name_cn": "圣安东尼安马刺", "gymnasium": "AT&T中心球馆", "championship": 5, "topStar": "蒂姆·邓肯", "date": "1995-04-12" } }, { "_index": "nba", "_type": "nba", "_id": "3", "_score": 1, "_source": { "name_en": "Golden State Warriors", "name_cn": "金州勇士队", "gymnasium": "甲骨文球馆", "championship": 6, "topStar": "斯蒂芬·库里", "date": "1949-06-13" } ··· } ] } } 响应的数据结果分为两部分 { ----------------first part-------------------- "took": 0, "timed_out": false, "_shards": { "total": 3, "successful": 3, "skipped": 0, "failed": 0 }, ---------------second part--------------------- "hits": { "total": 0, "max_score": null, "hits": [] } } 第一部分为:分片副本信息,第二部分 hits 包装的为查询的数据集。 注意:响应内容不仅会告诉我们哪些文档被匹配到,而且这些文档内容完整的被包含在其中—我们在给用户展示搜 索结果时需要用到的所有信息都有了。 # 查询英文名称为:"Golden State Warriors" 的球队信息 GET /nba/nba/_search { "query": { "match": { "name_en": "Golden State Warriors" } } } 可得到的查询结果为: { "took": 6, "timed_out": false, "_shards": { "total": 3, "successful": 3, "skipped": 0, "failed": 0 }, "hits": { "total": 1, "max_score": 1.9646256, "hits": [ { "_index": "nba", "_type": "nba", "_id": "3", "_score": 1.9646256, "_source": { "name_en": "Golden State Warriors", "name_cn": "金州勇士队", "gymnasium": "甲骨文球馆", "championship": 6, "topStar": "斯蒂芬·库里", "date": "1949-06-13" } } ] } } 2.过滤查询 Filter 我们让搜索变的复杂一些。我们想要找到当家球星是勒布朗·詹姆斯,但是我们只想得到总冠军多余1次的球队。我们的语句将做一些改变用来添加过滤器(filter),它允许我们有效的执行一个结构化搜索: GET /nba/nba/_search { "query": { "bool": { "filter": { "range": { "championship": { "gt": 1 } } }, "must": { "match": { "topStar": "勒布朗·詹姆斯" } } } } } 我们发现每次查询,查询结果里面都有一个 _score字段,一般Elasticsearch根据相关评分排序,相关评分是根据文档与语句的匹配度来得出, _score值越高说明匹配度越高。 Elasticsearch如何进行全文字段搜索且首先返回相关性性最大的结果。相关性(relevance)概念在Elasticsearch中非常重要,而这也是它与传统关系型数据库中记录只有匹配和不匹配概念最大的不同。 结束语 由于篇幅限制,对于 ElasticSearch 最基本的概念暂时先介绍这么多,要写的内容还很多,经过接近一个月的技术调研和开发,目前对于 ES 也有一个总体的技术了解,但是很多细节还是需要琢磨的,ES 的功能确实强大且丰富,要想熟练耍起来,还是需要一定时间的。 后面会继续介绍 ES的相关内容,大概包括 ES 服务的 Java 语言搭建,ES 的 SQL方式查询等等内容。有兴趣的可以先关注本人的博客,由于质量要求大概一星期更新一篇。 另外,我这里添加一个园友ReyCG对本篇文章的思维导图总结,通过该思维导图我们可以更加清晰的理解Elasticsearch的基础信息。

优秀的个人博客,低调大师

Aliyun LOG Java Producer 快速入门

背景 Aliyun LOG Java Producer 是为运行在大数据、高并发场景下的 Java 应用量身打造的高性能写 LogHub 类库。相对于原始的 API 或 SDK,使用 producer 写数据能为您带来诸多优势,包括高性能、计算与 I/O 逻辑分离、资源可控制等。想要更深入地了解 producer 的功能和原理可参考文章日志上云利器 - Aliyun LOG Java Producer,本文将聚焦于 producer 的使用上。 使用步骤 使用 producer 可归结为如下图所示的三个步骤,下面分别为您介绍。 创建 producer Producer 的创建过程主要涉及到以下对象。 ProjectConfig ProjectConfig 包含目标 project 的服务入口信息以及表征调用者身份的访问凭证。 服务入口 最终访问地址

优秀的个人博客,低调大师

Java入门系列-27-反射

咱们可能都用过 Spring AOP ,底层的实现原理是怎样的呢? 反射常用于编写工具,企业级开发要用到的 Mybatis、Spring 等框架,底层的实现都用到了反射。能用好反射,就能提高我们编码的核心能力。 反射机制 JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性。 作用: 在运行时判断任意一个对象所属的类 在运行时构造任意一个类的对象 在运行时判断任意一个类所具有的成员变量和方法 在运行时调用任意一个对象的成员变量和方法 生成动态代理 常用的类: java.lang.Class:代表一个类 java.lang.reflect.Method:代表类的方法 java.lang.reflect.Field:代表类的成员变量 java.lang.reflect.Constructor:代表类的构造方法 Class 类 Class 类的实例表示正在运行的 Java 应用程序中的类和接口,Class 没有公共构造方法,Class 对象是在加载类时由 Java 虚拟机及通过调用类加载器中的 defineClass 方法自动构造的。 一个类在 JVM 中只会有一个 Class 实例 一个 Class 对象对应的是一个加载到 JVM 中的一个 .class 文件 每个类的实例都会记得自己是由哪个 Class 实例所生成 通过 Class 可以完整地得到一个类中的完整结构 获取 Class 对象 获取 Class 对象有4种方式,前三种比较常用。 首先创建一个类用于测试 package com.jikedaquan.reflection; public class User { private int id; private String username; private String password; public User() { } public User(int id, String username, String password) { super(); this.id = id; this.username = username; this.password = password; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public void show() { System.out.println("Hello"); } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", password=" + password + "]"; } } 编写测试 package com.jikedaquan.reflection; public class GetClass { public static void main(String[] args) { //方法1 try { Class clz1=Class.forName("com.jikedaquan.reflection.User"); } catch (ClassNotFoundException e) { e.printStackTrace(); System.out.println("找不到指定类"); } //方法2 Class clz2=User.class; //方法3 User user=new User(); Class clz3=user.getClass(); //方法4 类的加载器 try { Class clz4=GetClass.class.getClassLoader().loadClass("com.jikedaquan.reflection.User"); } catch (ClassNotFoundException e) { e.printStackTrace(); System.out.println("找不到指定类"); } } } 方法1语法:Class Class对象 = Class.forName(包名+类名); 方法2语法:Class Class对象 = 类名.class; 方法3语法:Class Class对象 = 对象.getClass(); getClass() 方法是从 Object 类中继承过来的 获取类的结构 Class 类常用方法 方法名称 说明 Annotation[] getAnnotations() 返回此元素上存在的所有注解 Constructor getConstructor(Class<?>... parameterTypes) 获取指定参数的构造函数 Constructor<?>[] getConstructors() 返回包含的公有构造方法 Constructor<?>[] getDeclaredConstructors() 返回所有构造方法 Field getDeclaredField(String name) 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段 Method getDeclaredMethod(String name, Class<?>... parameterTypes) 根据方法名和参数获取方法对象 API 中可以看到有两种获取结构的方式:getDeclaredXxx()和getXxx();getDeclaredXxx()可以获取所有包括私有的 获取类的结构 package com.jikedaquan.reflection; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class GetClassStruct { public static void main(String[] args) { try { Class clz=Class.forName("com.jikedaquan.reflection.User"); System.out.println("===========构造==========="); //获取构造方法 Constructor[] cons=clz.getDeclaredConstructors(); for (Constructor constructor : cons) { System.out.println(constructor); } //获取字段 System.out.println("===========字段==========="); Field[] fields=clz.getDeclaredFields(); for (Field field : fields) { System.out.println(field); } //获取方法 System.out.println("===========方法==========="); Method[] methods=clz.getDeclaredMethods(); for (Method method : methods) { System.out.println(method); } //获取父类 System.out.println("===========父类==========="); Class supperClass=clz.getSuperclass(); System.out.println(supperClass.getName()); //获取实现的接口 System.out.println("===========接口==========="); Class[] interfaces=clz.getInterfaces(); for (Class interf : interfaces) { System.out.println(interf); } //获取注解 System.out.println("===========注解==========="); Annotation[] annotations=clz.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } } 调用类的指定方法、属性 获取构造方法并实例化对象 注意:jdk1.9弃用此方式实例化对象Object obj=clz.newInstance(); 通过反射获取有参或无参构造后方可实例化化对象 package com.jikedaquan.reflection; import java.lang.reflect.Constructor; public class CallConstructor { public static void main(String[] args) { //获取User 的 Class Class<User> clz=User.class; //获取无参构造方法并实例化 try { //getConstructor()方法不传参即无参 Constructor<User> constructor=clz.getConstructor(); User user=constructor.newInstance(); System.out.println(user); } catch (Exception e) { e.printStackTrace(); } //获取有参构造方法并实例化 try { Constructor<User> constructor=clz.getConstructor(int.class,String.class,String.class); User user=constructor.newInstance(18,"张三","abc123"); System.out.println(user); } catch (Exception e) { e.printStackTrace(); } } } 获取指定构造方法时,第二个参数为动态参数,不填写即获取无参构造方法,填写指定个数和指定类型.class可获取对应方式的构造方法。 调用类中的方法 package com.jikedaquan.reflection; import java.lang.reflect.Method; public class CallMethod { public static void main(String[] args) { //获取User 的 Class Class<User> clz=User.class; //获取无参方法 show try { Method method=clz.getMethod("show"); //执行clz中的方法 method.invoke(clz.getConstructor().newInstance()); } catch (Exception e) { e.printStackTrace(); } //获取一个参数为String的方法 try { Method method=clz.getMethod("setUsername", String.class); //反射实例化对象 User user=clz.getConstructor().newInstance(); //执行这个对象的方法 method.invoke(user, "反射"); //测试结果 System.out.println(user); } catch (Exception e) { e.printStackTrace(); } } } 如果有多个参数,获取方法:getMethod("方法名称",参数1.class,参数2.class,参数3.class) 多个参数执行时:method.invoke(对象,参数1,参数2,参数3); 动态代理 动态代理是指客户通过代理类来调用其他对象的方法,并且是在程序运行时根据需要创建目标类的代理对象。 原理: 使用一个代理将对象包装起来,然后用该代理对象取代原对象,任何对原始对象的调用都要通过dialing,代理对象决定是否以及何时将方法调用转到原始对象上。 生活中海外代购其实就用到了代理,你可能不方便出国,但是代购可以,最终帮你完成购买行为。 以代购为例子完成静态代理 package com.jikedaquan.reflection; //购买接口(约定) interface Buy{ void buyProduct(); } //被代理的 class Customer implements Buy{ @Override public void buyProduct() { System.out.println("购买商品"); } } //代理 class ProxyBuy implements Buy{ private Customer customer; public ProxyBuy(Customer customer) { this.customer=customer; } @Override public void buyProduct() { System.out.println("代理:出国"); //被代理的对象的行为 customer.buyProduct(); System.out.println("代理:回国"); } } public class TestStaticProxy { public static void main(String[] args) { Customer customer=new Customer(); ProxyBuy proxyBuy=new ProxyBuy(customer); proxyBuy.buyProduct(); } } 那么动态代理意味着不能只代理 Customer 类的行为,还可以代理其他类的行为 package com.jikedaquan.reflection; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //工厂接口 interface Factory{ void product(); } //电脑工厂 class ComputerFactory implements Factory{ @Override public void product() { System.out.println("生产电脑"); } } //动态代理处理器 class MyInvocationHandler implements InvocationHandler{ //要被代理的对象 private Object proxyObj; //产生代理对象 public Object bind(Object proxyObj) { this.proxyObj=proxyObj; return Proxy.newProxyInstance( proxyObj.getClass().getClassLoader(), proxyObj.getClass().getInterfaces(), this ); } //代理对象实际执行的方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理:收收费"); Object result=method.invoke(proxyObj, args); System.out.println("代理:代理完成"); return result; } } public class TestDynamicProxy { public static void main(String[] args) { //创建代理对象生产器 MyInvocationHandler invocationHandler=new MyInvocationHandler(); //创建要被代理的对象 ComputerFactory computerFactory=new ComputerFactory(); //生产代理对象 Object factoryProxy=invocationHandler.bind(computerFactory); Factory factory=(Factory) factoryProxy; factory.product(); //创建另一个要被代理的对象(上个示例静态代理的对象和接口) Customer customer=new Customer(); //生产代理对象 Object buyProxy=invocationHandler.bind(customer); Buy buy=(Buy) buyProxy; buy.buyProduct(); } } 在 main 方法中,创建了一个 MyInvocationHandler 对象,通过 bind 方法可以传入任意要被代理的对象,实现了动态。 重点来了,拿好小本子笔记!!!!! 实现动态代理的步骤: 1.创建要被代理的类的接口 2.创建要被代理的类实现类 3.创建代理对象处理器(MyInvocationHandler),实现 InvocationHandler 接口 4.编写生产代理对象的方法,方法内调用 Proxy.newInstance() 方法,返回代理对象 5.重写 InvocationHandler 的 invoke 方法 6.测试:创建代理对象生产器,生产代理对象

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册