首页 文章 精选 留言 我的

精选列表

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

设计模式入门-简单工厂模式

前言 话说设计模式是我们面试中经常遇到的问题,但是开发中遇到的也不少。之前一直想学设计模式,然后总结写一些文章,但一直忙于其它事情,现在终于要学习设计模式,参考的书籍是《大话设计模式》,这本书写得通俗易懂,推荐大家都去看一下。 场景描述 借用书中示例问题,计算两个数的加、减、乘、除等其它运算,一般我们的思维是自上而下处理问题,也就造成了运算两个数就要经过多次判断。 场景示例 两个数之前的算法运算,如下面代码所示: package me.xueyao; /** * @author Simon.Xue * @date 2019-12-30 22:54 **/ public class OperationHello { public static void main(String[] args) { System.out.println(getResult("*", 1, 3)); } public static int getResult(String operationStr, int number1, int number2) { int result = 0; switch (operationStr) { case "+": result = number1 + number2; break; case "-": result = number1 - number2; break; case "*": result = number1 * number2; break; case "/": result = number1 / number2; break; } return result; } } 此处的代码要判断四次,但是如果再增加其它的运算,会在原来基础上又增加条件判断。以后,随着业务有扩展会不停添加判断条件。代码的耦合度会越来越高,如果修改某一处运算的问题,就造成线上业务不能访问相关运算的功能,必须要修改好问题,其它的运算功能才能使用。 解决办法 现在可以用到我们所说的简单工厂模式,首先,我们要想,加、减、乘、除运算都属于运算子类,所以我们创建一个运算父类Operation .class package me.xueyao; /** * @author Simon.Xue * @date 2019-12-30 22:18 **/ public abstract class Operation { private int number1; private int number2; public int getNumber1() { return number1; } public void setNumber1(int number1) { this.number1 = number1; } public int getNumber2() { return number2; } public void setNumber2(int number2) { this.number2 = number2; } public abstract int getResult(); } 加、减、乘、除四则运算,我们分别创建OperationAdd.class,OperationSub.class,OperationMul.class,OperationDiv.class四个子类分别继承运算父类Operation.class, 实现其中计算方法。 package me.xueyao; /** * @author Simon.Xue * @date 2019-12-30 22:22 **/ public class OperationAdd extends Operation { @Override public int getResult() { return getNumber1() + getNumber2(); } } package me.xueyao; /** * @author Simon.Xue * @date 2019-12-30 22:22 **/ public class OperationSub extends Operation { @Override public int getResult() { return getNumber1() - getNumber2(); } } package me.xueyao; /** * @author Simon.Xue * @date 2019-12-30 22:25 **/ public class OperationMul extends Operation { @Override public int getResult() { return getNumber1() * getNumber2(); } } package me.xueyao; /** * @author Simon.Xue * @date 2019-12-30 22:26 **/ public class OperationDiv extends Operation { @Override public int getResult() { return getNumber1() / getNumber2(); } } 当我们要使用运算方法时,只需要创建其对象,再执行计算方法,便可计算两个数的运算,但是现在又有一个问题,就是每种运算方式都要创建对象。都要暴露父类对象,我们可以创建一个工厂类,由工厂类来创建所需要的对象,如下代码如示 package me.xueyao; /** * @author Simon.Xue * @date 2019-12-30 22:30 **/ public class OperationFactory { public static Operation createOperation(String operationStr) { Operation operation = null; switch (operationStr) { case "+": operation = new OperationAdd(); break; case "-": operation = new OperationSub(); break; case "*": operation = new OperationMul(); break; case "/": operation = new OperationDiv(); break; } return operation; } } 总结 简单工厂模式,是设计模式中比较简单的一种模式,但是它每多出一种需求,就要创建一个类,总体来说用起来还不错。文章如有问题,请联系我。

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

Tablestore入门手册--表(Table)管理

表管理接口概述 API 描述 createTable 创建表 deleteTable 删除表 listTable 列出实例下的所有表 updateTable 更新表(在表被创建之后,动态的更改表的配置或预留吞吐量) describeTable 获取表的详细信息 上述API操作是Tablestore最基础的API。官方提供了Java、Go、Node.js、Python、PHP、C#、C++语言的SDK。 createTable 创建表可以在控制台进行。在使用API进行创建的时候,需要指定表的配置信息和预留吞吐量等信息。 说明: 表格创建好后服务端有初始化时间,需要等待几秒钟才能对表进行读写,否则会出现异常 表限制 单个实例最多可以创建 64 张数据表 表名长度1-255 Bytes,需由[a-z, A-Z, 0-9]和下划线(_)组成。首字符必须是字母或下划线(_) 其它限制见: https://help.aliyun.com/document_detail/91524.html?spm=a2c4g.11186623.6.568.357f228382mAWN 参数说明 创建表的参数主要包括如下几部分: TableMeta: 表的结构信息,包含表的名称以及表的主键定义 TableOptions: 表的配置选项,用于配置TTL、MaxVersions等 ReservedThroughput:表的预留读写吞吐量设置 表结构 TableMeta 参数 定义 说明 TableName 表名 无 List 表的主键定义 1. 注意: 最多可设置 4 个主键,主键的配置及顺序一旦设置便不可修改。 2. 表格存储可包含多个主键列。主键列是有顺序的,与用户添加的顺序相同,例如, PRIMARY KEY (A, B, C) 与 PRIMARY KEY (A, C, B) 是不同的两个主键结构。表格存储会按照主键的大小为行排序,具体参见表格存储数据模型和查询操作。3. 第一列主键作为分片键。分片键相同的数据会存放在同一个分片内,所以相同分片键下最好不要超过 10 G 以上数据,否则会导致单分片过大,无法分裂。另外,数据的读/写访问最好在不同的分片键上均匀分布,有利于负载均衡。4. 属性列不需要定义。表格存储每行的数据列都可以不同,属性列的列名在写入时指定。 表配置 TableOptions 预留吞吐量 ReservedThroughtput ReservedThroughtput表的预留读/写吞吐量配置。 设置 ReservedThroughtput 后,表格存储按照您预留读/写吞吐量进行计费。 当 ReservedThroughtput 大于 0 时,表格存储会按照预留量和持续时间进行计费,超出预留的部分进行按量计费。更多信息参见计费,以免产生未期望的费用。 默认值为 0,即完全按量计费。 容量型实例的预留读/写吞吐量只能设置为 0,不允许预留。 Java代码示例 // 创建普通表(不使用索引等功能) public void createTable() { TableMeta tableMeta = new TableMeta(TABLE_NAME); // 为主表添加主键列。 tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema("pk_1", PrimaryKeyType.STRING)); tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema("pk_2", PrimaryKeyType.INTEGER)); tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema("pk_3", PrimaryKeyType.BINARY)); // 设置该主键为自增列 tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema("pk_4", PrimaryKeyType.INTEGER, PrimaryKeyOption.AUTO_INCREMENT)); // 数据的过期时间,单位秒, -1代表永不过期,例如设置过期时间为一年, 即为 365 * 24 * 3600。 int timeToLive = -1; // 保存的最大版本数,设置为3即代表每列上最多保存3个最新的版本。(如果使用索引,maxVersions只能等于1) int maxVersions = 3; TableOptions tableOptions = new TableOptions(timeToLive, maxVersions); CreateTableRequest request = new CreateTableRequest(tableMeta, tableOptions); // 设置读写预留值,容量型实例只能设置为0,高性能实例可以设置为非零值。 request.setReservedThroughput(new ReservedThroughput(new CapacityUnit(0, 0))); client.createTable(request); } 表设计相关技巧 分区键选择 表格存储Tablestore第一个主键是分区键,决定了数据分布式存储的位置。分区键的选择决定了数据是否均匀散列在不同的后端服务器上。散列是分布式数据库中常见的问题之一,数据的散列能够避免热点问题。因此在选择主键的时候,首先要选好分区键。其中比较常用的两种方式如下: 分区键可以选择业务上比较分散的Key放到第一列,如userID、DeviceId等。如果每个用户数据分布严重不均匀,则需要另外选择其它字段。 如果分区键不好设计,可以对想要当做分区键的值拼接MD5,这样能够保证数据散列。 更多的设计技巧见两篇表设计实践。 表设计的最佳实践 、表设计实践 数据生命周期TTL设计 数据生命周期(Time To Live,简称 TTL)是数据表的一个特性,即数据的存活时间,单位为秒。表格存储会在后台对超过存活时间的数据进行清理,以减少用户的数据存储空间,降低存储成本。 TTL特性能够实现数据过期自动删除,因此在很多场景能够用到,这些场景中随着时间的流逝数据的价值会降低,特别适合TTL。 舆情监控。如果用户只关心最近3个月的信息,因此超过3个月的数据可以自动删除。 物流轨迹。物流轨迹的记录信息在用户收到货物后就失去了其大部分的价值,因此可以设置1个月的TTL,来节省大量的存储费用。 系统日志。系统的运行日志大多数只有在系统出问题时候才会查看,而随着时间流逝,很早之前的系统日志也就失去了存在的价值,而这部分数据存储在数据库中会占用存储成本,设置合适的TTL能够自动将之前的数据删除。 TTL暂时仅支持主表,索引等还暂时不支持TTL特性。因此如果使用了二级索引或者多元索引,需要主表的TTL=-1,即永久不会失效,对于已经创建好表的用户,可以通过 UpdateTable 接口动态更改主表的 TTL。 Java 示例代码 public void updateTTL() { UpdateTableRequest request = new UpdateTableRequest(TABLE_NAME); int ttl = -1; request.setTableOptionsForUpdate(new TableOptions(ttl)); client.updateTable(request); } 主键自增 主键列自增功能是指若用户指定某一列主键为自增列,在其写入数据时,表格存储会自动为用户在这一列产生一个新的值,且这个值为同一个分区键下该列的最大值。 主键自增列的功能特性主要有生成数字ID且ID严格递增保证顺序,这个特性决定了许多场景能够使用。 如电商网站的商品 ID、大型网站的用户 ID等,这些场景中数值越大,表示该商品、用户越新。 如论坛帖子的 ID、聊天工具的消息 ID等消息保序的场景,这些场景需要严格保证消息递增,不然用户读取到的顺序就会乱序。举个例子,假如用户发朋友圈场景,用户在1点5分11.1秒时刻发送了一个朋友圈记录a,另一个用户在1点5分11.2秒发送了一个朋友圈记录b,则需要严格保证记录b的id比记录a的id大。主键自增在聊天系统IM中的应用见 Table Store主键列自增功能在IM系统中的应用 主键自增的一些限制: 表格存储支持多个主键,第一个主键为分区键,分区键不允许设置为自增列,其它任一主键都可以设置为自增列。 每张表最多只允许设置一个主键为自增列。 属性列不能设置为自增列。 仅支持在创建表的时候指定自增列,对于已存在的表不支持创建自增列。 Java示例代码 // 主键自增 创建主表 public void createTableWithPKAutoIncrement() { TableMeta tableMeta = new TableMeta(TABLE_NAME + "AUTO_INCREMENT"); tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema("pk_1", PrimaryKeyType.STRING)); // 设置该主键为自增列 tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema("pk_autoI_increment", PrimaryKeyType.INTEGER, PrimaryKeyOption.AUTO_INCREMENT)); tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema("pk_3", PrimaryKeyType.INTEGER)); TableOptions tableOptions = new TableOptions(-1, 1); CreateTableRequest request = new CreateTableRequest(tableMeta, tableOptions); client.createTable(request); } // 自增列的数据插入 public void putRow(){ PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder() .addPrimaryKeyColumn("pk_1", PrimaryKeyValue.fromString("test1")) .addPrimaryKeyColumn("pk_auto_increment", PrimaryKeyValue.AUTO_INCREMENT) .addPrimaryKeyColumn("pk_3", PrimaryKeyValue.fromLong(100)) .build(); RowPutChange rowPutChange = new RowPutChange(TABLE_NAME , primaryKey); rowPutChange.addColumn("attr_1", ColumnValue.fromLong(100)); PutRowRequest request = new PutRowRequest(rowPutChange); client.putRow(request); } deleteTable 删除表,只需要指定表名字即可。 说明: 如果表中创建了多元索引,需要先删除多元索引才可以删除表。 Java代码示例 public void deleteTable() { DeleteTableRequest request = new DeleteTableRequest(TABLE_NAME); client.deleteTable(request); } listTable 该API能够列出当前实例下已创建的所有表的表名。 Java代码示例 public void listTable() { ListTableResponse response = client.listTable(); System.out.println("表的列表如下:"); for (String tableName : response.getTableNames()) { System.out.println(tableName); } } updateTable 该API能够动态的更改表的配置或预留吞吐量。可以只修改配置或只修改预留吞吐量,也可以一起修改。 说明: 该API调用频率有限制,为每 2分钟1次。 Java代码示例 public void updateTable() { UpdateTableRequest request = new UpdateTableRequest(TABLE_NAME); // 修改预留吞吐 request.setReservedThroughputForUpdate(new ReservedThroughput(new CapacityUnit(0, 0))); // 修改表的最大保留版本、TTL等 request.setTableOptionsForUpdate(new TableOptions(-1, 1)); client.updateTable(request); } describeTable 该API可以获得表的结构信息(TableMeta)、配置信息(TableOptions)和预留读/写吞吐量的情(ReservedThroughputDetails,包括调整时间)、表分区信息等, 如图所示。 Java代码示例 public void describeTable() { DescribeTableRequest request = new DescribeTableRequest(TABLE_NAME); DescribeTableResponse response = client.describeTable(request); TableMeta tableMeta = response.getTableMeta(); System.out.println("表的名称:" + tableMeta.getTableName()); System.out.println("表的主键:"); for (PrimaryKeySchema schema : tableMeta.getPrimaryKeyList()) { System.out.println("\t主键名字:" + schema.getName() + "\t主键类型:" + schema.getType() + "\t自增列:" + (schema.getOption() == null ? "false" : schema.getOption().equals(PrimaryKeyOption.AUTO_INCREMENT))); } System.out.println("预定义列信息:"); for (DefinedColumnSchema schema : tableMeta.getDefinedColumnsList()) { System.out.println("\t主键名字:" + schema.getName() + "\t主键类型:" + schema.getType()); } System.out.println("二级索引信息:"); for (IndexMeta meta : response.getIndexMeta()) { System.out.println("\t索引名字:" + meta.getIndexName()); System.out.println("\t\t索引类型:" + meta.getIndexType()); System.out.println("\t\t索引主键:" + meta.getPrimaryKeyList()); System.out.println("\t\t索引预定义列:" + meta.getDefinedColumnsList()); } TableOptions tableOptions = response.getTableOptions(); System.out.println("TableOptions:"); System.out.println("\t表的TTL:" + tableOptions.getTimeToLive()); System.out.println("\t表的MaxVersions:" + tableOptions.getMaxVersions()); ReservedThroughputDetails rtd = response.getReservedThroughputDetails(); System.out.println("预留吞吐量:"); System.out.println("\t读:" + rtd.getCapacityUnit().getReadCapacityUnit()); System.out.println("\t写:" + rtd.getCapacityUnit().getWriteCapacityUnit()); System.out.println("\t最近上调时间: " + new Date(rtd.getLastIncreaseTime() * 1000)); System.out.println("\t最近下调时间: " + new Date(rtd.getLastDecreaseTime() * 1000)); List<PrimaryKey> shardSplits = response.getShardSplits(); System.out.println("表分区信息:"); for (PrimaryKey primaryKey : shardSplits) { System.out.println("\t分裂点信息: " + primaryKey.getPrimaryKeyColumnsMap()); } } 专家服务 如有疑问或者需要更好的在线支持,欢迎加入钉钉群:“表格存储公开交流群”(群号:23307953)。群内提供免费的在线专家服务,欢迎扫码加入。

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

Python入门你要懂哪些?

前言 什么是计算机语言 计算机就是一台用来计算的机器,人让计算机干什么计算机就得干什么! 需要通过计算机的语言来控制计算机(也就是编程语言)! 计算机语言其实和人类的语言没有本质的区别,不同点就是交流的主体不同!计算机语言发展经历了三个阶段: 1). 机器语言 机器语言通过二进制编码来编写程序 执行效率好,编写起来太麻烦 2). 符号语言(汇编) 使用符号来代替机器码 编写程序时,不需要使用二进制, 而是直接编写符号 编写完成后,需要将符号转换为机器码,然后再由计算机执行符号转换为机器码的过程称为汇编 将机器码转换为符号的过程,称为反汇编 汇编语言一般只适用于某些硬件,兼容性比较差 3). 高级语言 高级语言的语法基本和现在英语语法类似,并且和硬件的关系没有那么紧密了。也就是说我们通过高级语言开发程序可以在不同的硬件系统中执行 并且高级语言学习起来也更加的容易,现在我们知道的语言基本都是高级语言 如:C、 C++、C#、Java、JavaScript、Python 等.. 编译型语言和解释型语言 计算机只能识别二进制编码(机器码),所以任何的语言在交由计算机执行时必须要先转换为机器码,也就是像 print('hello') 必须要转换为类似 1010101 这样的机器码。 根据转换时机的不同,语言分成了两大类: 1). 编译型语言 如:C语言 编译型语言,会在代码执行前将代码编译为机器码,然后将机器码交由计算机执行 执行过程:a(源码) --编译--> b(编译后的机器码) 特点: 执行速度特别快 跨平台性比较差 2). 解释型语言 如:Python JS Java 解释型语言,不会在执行前对代码进行编译,而是在执行的同时一边执行一边编译 执行过程:a(源码)--解释器--> 解释执行 特点: 执行速度比较慢 跨平台性比较好 下面我们切入正题,谈谈Python。 Python的介绍 Python是解释型语言。 Python(英国发音:/ˈpaɪθən/ 美国发音:/ˈpaɪθɑːn/),是一种广泛使用的高级编程语言,属于通用型编程语言,由吉多·范罗苏姆创造,第一版发布于1991年。可以视之为一种改良(加入一些其他编程语言的优点,如面向对象)的LISP。作为一种解释型语言,Python的设计哲学强调代码的可读性和简洁的语法(尤其是使用空格缩进划分代码块,而非使用大括号或者关键词)。相比于C++或Java,Python让开发者能够用更少的代码表达想法。不管是小型还是大型程序,该语言都试图让程序的结构清晰明了。 Python的用途: WEB应用 Facebook 豆瓣 爬虫程序 科学计算 自动化运维 大数据(数据清洗) 云计算 桌面软件/游戏 人工智能 Python开发环境搭建 开发环境搭建就是安装Python的解释器 Python的解释器分类: CPython(官方)用c语言编写的Python解释器 PyPy用Python语言编写的Python解释器 IronPython用.net编写的Python解释器 JPython用Java编写的Python解释器 步骤: 1.下载安装包 python-3.6.exe2.安装(傻瓜式安装, 默认选项..) 安装完成可以看到以下几个程序: 3.打开命令行窗口,输入python 出现如下内容Python的交互界面 当我们通过Windows命令行来输入Python,所进入到的界面就是Python的交互界面 结构: 版本和版权声明: Python 3.6.3 (tags/v3.6.3:2c5fed8, Oct 3 2017, 17:26:49) [MSC v.1900 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. 命令提示符: >>> 在命令提示符后可以直接输入Python的指令!输入完的指令将会被Python的解释器立即执行! 安装Python的同时,会自动安装一个Python的开发工具IDLE,通过IDLE也可以进入到交互模式。但是不同的是,在IDLE中可以通过TAB键来查看语句的提示。 IDLE实际上就是一个交互界面,但是他可以有一些简单的提示,并且可以将代码保存。 注意:交互模式只能你输入一行代码,它就是执行一行,所以他并不适用于我们日常的开发! 仅可以用来做一些日常的简单的测试! 我们一般会将Python代码编写到一个py文件中,然后通过python指令来执行文件中的代码。 Python和Sublime的整合 1.在Sublime中执行Python代码,按 ctrl + b 可以自动在Sublime内置的控制台中执行 这种执行方式,在某些版本的Sublime中对中文支持不好,并且不能使用input()函数。 2.使用SublimeREPL来运行python代码 如下图:选择SublimeREPL-> Python来执行Python代码但是这样很麻烦。为方便我们可以设置快捷键,按f5则自动执行当前的Python代码。 如下设置快捷键来执行python代码呢? 找到Preferences-->Key Bindings ,然后复制下面的内容到右边的中括号内。然后保存。 这样我们就可以按F5快捷键来自动执行当前的Python代码了。 { "keys": ["f5"], "caption": "SublimeREPL:Python","command": "run_existing_window_command", "args":{"id": "repl_python_run","file": "config/Python/Main.sublime-menu"}}, Python的几个基本概念 1.表达式 表达式就是一个类似于数学公式的东西 比如:10 + 5 8 - 4 表达式一般仅仅用了计算一些结果,不会对程序产生实质性的影响 如果在交互模式中输入一个表达式,解释器会自动将表达式的结果输出 2.语句 在程序中语句一般需要完成某种功能,比如打印信息、获取信息、为变量赋值比如: #Python学习交流QQ群:857662006 print() input() a = 10 语句的执行一般会对程序产生一定的影响 在交互模式中不一定会输出语句的执行结果 3.程序(program) 程序就是由一条一条的语句和一条一条的表达式构成的。 4.函数(function) 函数就是一种语句,函数专门用来完成特定的功能函数长的形如:xxx() 函数的分类: 1). 内置函数 由Python解释器提供的函数,可以在Python中直接使用 2). 自定义函数 由程序员自主的创建的函数 当我们需要完成某个功能时,就可以去调用内置函数,或者自定义函数 函数的两个要素: 1). 参数 ()中的内容就是函数的参数 函数中可以没有参数,也可以有多个参数,多个参数之间使用,隔开 2). 返回值 返回值是函数的返回结果,不是所有的函数都有返回值 Python的基本语法 在Python中严格区分大小写 Python中的每一行就是一条语句,每条语句以换行结束 Python中每一行语句不要过长(规范中建议每行不要超过80个字符) 一条语句可以分多行编写,多行编写时语句后边以结尾 Python是缩进严格的语言,所以在Python中不要随便写缩进 在Python中使用#来表示注释,#后的内容都属于注释,注释的内容将会被解释器所忽略 我们可以通过注释来对程序进行解释说明,一定要养成良好的编写注释的习惯注释要求简单明了,一般习惯上#后边会跟着一个空格 字面量和变量 字面量就是一个一个的值,比如:1,2,3,4,5,6,‘HELLO’ 字面量所表示的意思就是它的字面的值,在程序中可以直接使用字面量 变量(variable)变量可以用来保存字面量,并且变量中保存的字面量是不定的 变量本身没有任何意思,它会根据不同的字面量表示不同的意思 一般我们在开发时,很少直接使用字面量,都是将字面量保存到变量中,通过变量来引用字面量 数据类型 数据类型指的就是变量的值得类型,也就是可以为变量赋哪些值 在Python中,能够直接处理的数据类型有以下几种:整数、浮点数、字符串、布尔值、列表、元组、字典、集合。 以后我们详细介绍这几个数据类型。 对象(object) Python是一门面向对象的语言 一切皆对象! 程序运行当中,所有的数据都是存储到内存当中然后再运行的! 对象就是内存中专门用来存储指定数据的一块区域 对象实际上就是一个容器,专门用来存储数据 像我们之前学习的数值、字符串、布尔值、None都是对象 对象的结构 每个对象中都要保存三种数据 1). id(标识) id用来标识对象的唯一性,每一个对象都有唯一的id 对象的id就相当于人的身份证号一样 可以通过id()函数来查看对象的id id是由解析器生成的,在CPython中,id就是对象的内存地址 对象一旦创建,则它的id永远不能再改变 2). type(类型) 类型用来标识当前对象所属的类型 比如:int str float bool 类型决定了对象有哪些功能 通过type()函数来查看对象的类型 Python是一门强类型的语言,对象一旦创建类型便不能修改 3). value(值) 值就是对象中存储的具体的数据 对于有些对象值是可以改变的 对象分成两大类,可变对象 不可变对象 可变对象的值可以改变 不可变对象的值不能改变 变量和对象 对象并没有直接存储到变量中,在Python中变量更像是给对象起了一个别名 变量中存储的不是对象的值,而是对象的id(内存地址), 当我们使用变量时,实际上就是在通过对象id在查找对象 变量中保存的对象,只有在为变量重新赋值时才会改变 变量和变量之间是相互独立的,修改一个变量不会影响另一个变量 类型转换 所谓的类型转换,将一个类型的对象转换为其他对象 类型转换不是改变对象本身的类型,而是根据当前对象的值创建一个新对象 运算符(操作符) 运算符可以对一个值或多个值进行运算或各种操作 比如 + 、-、= 都属于运算符 运算符的分类: 1.算术运算符2.赋值运算符3.比较运算符(关系运算符)4.逻辑运算符5.条件运算符(三元运算符)

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

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只是常用的端口。 最后这几天玩了一下阿里云服务器,学到了不少,来分享了一下,有些乱,还有些东西没写上来, 剩下的就是远程连接你的服务器,玩它就行了。了解更多产品详情可点击加关注

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

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

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册