首页 文章 精选 留言 我的

精选列表

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

初识 sqlite 与 content provider 学习笔记

1,SQLite 简单使用 1,SQLite支持的数据类型 NULL. The value is a NULL value. INTEGER. The value is a signed integer, stored in 1, 2, 3, 4, 6, or 8 bytes depending on the magnitude of the value. REAL. The value is a floating point value, stored as an 8-byte IEEE floating point number. TEXT. The value is a text string, stored using the database encoding (UTF-8, UTF-16BE or UTF-16LE). BLOB. The value is a blob of data, stored exactly as it was input. 2,相关数据库定义数据类型词与SQLite数据类型的关联表 Example Typenames From The CREATE TABLE Statement or CAST Expression Resulting Affinity Rule Used To Determine Affinity INT INTEGER TINYINT SMALLINT MEDIUMINT BIGINT UNSIGNED BIG INT INT2 INT8 INTEGER 1 CHARACTER(20) VARCHAR(255) VARYING CHARACTER(255) NCHAR(55) NATIVE CHARACTER(70) NVARCHAR(100) TEXT CLOB TEXT 2 BLOBno datatype specified NONE 3 REAL DOUBLE DOUBLE PRECISION FLOAT REAL 4 NUMERIC DECIMAL(10,5) BOOLEAN DATE DATETIME NUMERIC 5 把数据类型搞定了…我们就开始使用我们的android的sqlite了… 第一步:实现一个SQLiteOpenHelper类 //创建一个继承SQLiteOpenHelper类 publicclassMyOpenHelperextendsSQLiteOpenHelper{ //必须实现的一个构造方法publicMyOpenHelper(Contextcontext,Stringname,CursorFactoryfactory,intversion){super(context,name,factory,version); //TODOAuto-generatedconstructorstub} //设置数据库初始化版本号 privatestaticfinalintDATABASE_VERSION=1; //设置数据库创建的表名 privatestaticfinalStringTABLE_NAME="users"; //构建创建表的SQL的语句 privatestaticfinalStringTABLE_CREATE_SQL="CREATETABLE"+ TABLE_NAME+"(idINTEGERprimarykey,nameTEXT)"; //自定义构造方法传入content,与数据库名字 publicMyOpenHelper(Contextcontext,Stringname){this(context,name,null,DATABASE_VERSION);} //自定义构造方法传入用来升级数据库的版本号 publicMyOpenHelper(Contextcontext,Stringname,intversion){ this(context,name,null,version);}@OverridepublicvoidonCreate(SQLiteDatabasedb){ //TODOAuto-generatedmethodstub Log.d("sqlite","sql-->CreateTable"+TABLE_CREATE_SQL); db.execSQL(TABLE_CREATE_SQL);} @Override publicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){ //TODOAuto-generatedmethodstub}} ok 第二步:使用MyOpenHelper //某 String dataBaseName = "employee"'; MyOpenHelper moh = new MyOpenHelper(Sqlite_contentproviderActivity.this,dataBaseName ); SQLiteDatabase sdb = moh.getReadableDatabase(); toastSQL = Toast.makeText(context, "创建数据库成功", Toast.LENGTH_LONG); toastSQL.show(); 1,我们到adb 中查看在设备中我们保存的数据库文件在 cd /data/data/<package_name>/databases 2,ls 命令看下 3,用sqlite3命令进入数据库 这样我们就看到我们刚才创建的表了… 这里给出插入操作的代码 StringdatabaseName="employee"; MyOpenHelpermoh=newMyOpenHelper(Sqlite_contentproviderActivity.this,databaseName); //获取一个可写操作 SQLiteDatabasesdb=moh.getWritableDatabase(); ContentValuescv=newContentValues(); String[]name={"tom","achai","nevin","week"}; for(inti=0;i<name.length;i++){ cv.put("name",name[i]); sdb.insert("users",null,cv); } 剩下的操作…请阅读官方文档SQLiteDatabase里面的方法 2,创建属于自己的content provider 1,建立一个属于自己的content provider你必须要做 设置一个存储数据的地方,可以使用android 提供的文件存储方法,或者使用SQLite databases,然而,你可以存储任何你想要的数据,android提供的SQLiteOpenHelper可以帮助你创建属于和管理你自己的数据库, 实现ContentProvider 提供用于访问数据的类 在AndroidManifest.xml,声明你的 content provider 2,编写一个数据工具类 publicclassContentProviderData{ publicstaticfinalStringAUTHORIY="kg.tom.FirstProvider"; publicclassContentProviderData{ //定义我们provider使用的认证uri publicstaticfinalStringAUTHORIY="kg.tom.FirstProvider"; //定义我们数据库的名字 publicstaticfinalStringDATABASE_NAME="kg_tom_pro_test"; //定义数据库的版本号 publicstaticfinalintDATABASE_VERSION=1; //定义创建表的名字 publicstaticfinalStringUSERS_TABLE_NAME="users"; //实现BaseColums,自带两列,_id,_count publicstaticfinalclassUserTableMetaDataimplementsBaseColumns{ //定义创建表的名字 publicstaticfinalStringTABLE_NAME="users"; //定义provider的uri publicstaticfinalUriCONTENT_URI=Uri.parse("content://"+AUTHORIY+"/users"); //定义一条数据的类型 publicstaticfinalStringCONTENT_TYPE="vnd.android.cursor.dir/vnd.firstprovider.user"; //定义一组数据的类型 publicstaticfinalStringCONTENT_TYPE_ITEM="vnd.android.cursor.item/vnd.firsstprovider.user"; //定义列名 publicstaticfinalStringUSER_NAME="name"; //定义排序规则 publicstaticfinalStringDEFULT_SORT_ORDER="_iddesc"; }} 2,继承content provider 类 继承这个类我们同时要实现以下几个方法: query()insert()update()delete()getType()onCreate() 还有必须添加一个UriMatcher对象 关于UriMatcher对象的使用文档有很好的解释 //定义URI标识符,数值定义请参考文档 publicstaticfinalintINCOMING_USER_COLLECTION=1; publicstaticfinalintINCOMING_USER_SINGLE=2; //定义UriMatcher对象 publicstaticfinalUriMatcheruMatcher; //把标识符加入到URI中,固定写法 static{ uMatcher=newUriMatcher(UriMatcher.NO_MATCH); //第一个参数为 contentproviderauthoriy uMatcher.addURI(AUTHORIY,"users",INCOMING_USER_COLLECTION); uMatcher.addURI(AUTHORIY,"users/#",INCOMING_USER_SINGLE);} 一个完整的content provider publicclassFirstProviderextendsContentProvider{ //定义URI标识符 publicstaticfinalintINCOMING_USER_COLLECTION=1; publicstaticfinalintINCOMING_USER_SINGLE=2; //定义UriMatcher对象 publicstaticfinalUriMatcheruMatcher; //把标识符加入到URI中,固定写法 static{ uMatcher=newUriMatcher(UriMatcher.NO_MATCH);uMatcher.addURI(ContentProviderData.AUTHORIY,"users",INCOMING_USER_COLLECTION); uMatcher.addURI(ContentProviderData.AUTHORIY,"users/#",INCOMING_USER_SINGLE);} //这里是定义查询用的列名的别名 publicstaticHashMap<String,String>userMap; privateDataBaseHelperdh; static{ userMap=newHashMap<String,String>(); userMap.put(UserTableMetaData._ID,"id"); userMap.put(UserTableMetaData.USER_NAME, UserTableMetaData.USER_NAME);} @Override publicintdelete(Uriuri,Stringselection,String[]selectionArgs){ //TODOAuto-generatedmethodstub return0;} //根据传入的URI @Override publicStringgetType(Uriuri){ //TODOAuto-generatedmethodstub Log.d("sqlite","getType-->"); switch(uMatcher.match(uri)){ caseINCOMING_USER_COLLECTION: returnUserTableMetaData.CONTENT_TYPE; caseINCOMING_USER_SINGLE: returnUserTableMetaData.CONTENT_TYPE_ITEM;default: thrownewIllegalArgumentException("unKnownuri"+uri);}} @Override publicUriinsert(Uriuri,ContentValuesvalues){ //TODOAuto-generatedmethodstub Log.d("insert","class"+getClass()); Log.d("insert","content"+getContext()); SQLiteDatabasedb=dh.getWritableDatabase(); longrowId=db.insert(UserTableMetaData.TABLE_NAME,null,values); if(rowId>0){ UriinsertUri=ContentUris.withAppendedId (UserTableMetaData.CONTENT_URI,rowId); getContext().getContentResolver().notifyChange(insertUri,null); returninsertUri;} returnnull;} @Override publicbooleanonCreate(){ //TODOAuto-generatedmethodstub Log.d("sqlite","createPro--->"); dh=newDataBaseHelper(getContext(),ContentProviderData.DATABASE_NAME); //SQLiteDatabasedb=dh.getReadableDatabase();returntrue;} @Override publicCursorquery(Uriuri,String[]projection,Stringselection, String[]selectionArgs,StringsortOrder){ //TODOAuto-generatedmethodstub SQLiteQueryBuilderqb=newSQLiteQueryBuilder(); switch(uMatcher.match(uri)){ caseINCOMING_USER_COLLECTION: qb.setTables(UserTableMetaData.TABLE_NAME); qb.setProjectionMap(userMap); break; caseINCOMING_USER_SINGLE: qb.setTables(UserTableMetaData.TABLE_NAME); qb.setProjectionMap(userMap); qb.appendWhere(UserTableMetaData._ID+"="+ uri.getPathSegments().get(1)); break;} StringorderBy; if(TextUtils.isEmpty(sortOrder)){ orderBy=UserTableMetaData.DEFULT_SORT_ORDER;}else{ orderBy=sortOrder;} SQLiteDatabasedb=dh.getWritableDatabase(); Cursorc=qb.query(db,projection,selection, selectionArgs,null,null,sortOrder); c.setNotificationUri(getContext().getContentResolver(),uri); Log.d("sqlite","first--->>");returnc;} @Override publicintupdate(Uriuri,ContentValuesvalues,Stringselection, String[]selectionArgs){ //TODOAuto-generatedmethodstub return0;}} 3,在activity中的方法中用上这几行代码就可以进行插入 //定义插入用数据的对象,本质是一个 mapContentValuesvalues=newContentValues(); //键,值对values.put("id",1); //定义表名 Stringname=ContentProviderData.USERS_TABLE_NAME; //键值对 values.put(ContentProviderData.UserTableMetaData.USER_NAME,"tom"); //进行contentprovider的插入操作 Uriuri=getContentResolver().insert( ContentProviderData.UserTableMetaData.CONTENT_URI,values); 至于剩下的 query() delete() 自己参照文档补全吧 本文转自 liam2199 博客,原文链接:http://blog.51cto.com/youxilua/773107 如需转载请自行联系原作者

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

openstack学习笔记一 RDO模式安装

SaaS 软件即服务 PasS 平台 IaaS 基础设施 XaaS 一切皆服务 openstack版本 liberty版本 自由 mitaka版本 最新版 [日本] 三鹰 开源项目:RDO packstack工具来安装openstack alinone 所有的组件全部安装,而且不好定制,只适合于测试环境 注意:当我们使用alinone安装的时候,会从互联网上下载一个镜像cirros 应答文件 环境: [root@h1 ~]# cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core) 网络配置: 控制节点: 192.168.1.201 h1.hequan.com h1 结算节点: 192.168.1.202 h2.hequan.com h2 openstack RDO安装 1 2 3 4 [root@h1~] #systemctlis-activeNetworkManager active [root@h1~] #systemctlstopNetworkManager [root@h1~] #systemctldisableNetworkManager 软件 http://mirrors.163.com/centos/7.2.1511/cloud/x86_64/ 根据版本下载下来, 此次安装的是liberty版本 修改yum源 1 2 3 4 5 6 [openstack] name=openstack baseurl= ##把下载的软件放到此目录 enabled=1 gpgcheck=0 yumcleanall 1 2 3 4 5 6 7 8 9 10 11 12 13 [root@h1openstack] #yumlistopenstack-packstack 已加载插件:fastestmirror dvd|3.6kB00:00:00 openstack|2.9kB00:00:00 (1 /3 ):dvd /group_gz |155kB00:00:00 (2 /3 ):openstack /primary_db |656kB00:00:00 (3 /3 ):dvd /primary_db |2.8MB00:00:00 Determiningfastestmirrors 可安装的软件包 openstack-packstack.noarch1:7.0.0-0.10.dev1682.g42b3426.el7openstack yum install openstack-packstack alinonea安装方式 1 2 3 4 5 [root@h1openstack] #packstack--help|grepdemo Provisioningdemoconfig: --provision-demo=PROVISION_DEMO Specify 'y' toprovision for demousageandtesting. [root@h1openstack] #packstack--allinone--provision-demo=n##全部安装 应答文件安装 1 2 3 4 5 6 7 8 9 10 11 12 13 [root@h1~] #packstack--help|grepans --gen-answer- file =GEN_ANSWER_FILE Generateatemplateofananswer file . --answer- file =ANSWER_FILE [root@h1~] #packstack--gen-answer-file=he.txt 67CONFIG_NAGIOS_INSTALL=n 1116CONFIG_PROVISION_DEMO=n [root@h1~] #grep_PWhe.txt [root@h1~] #sed-i.bak-r's/(.+_PW)=.+/\1=hequan/'he.txt##替换密码 [root@h1~] #packstack--answer-file=he.txt##开始安装 1 2 3 4 5 6 7 8 9 ****Installationcompletedsuccessfully****** Additionalinformation: *Timesynchronizationinstallationwasskipped.Pleasenotethatunsynchronized time onserverinstancesmightbeproblem for someOpenStackcomponents. *File /root/keystonerc_admin hasbeencreatedonOpenStackclienthost192.168.1.201.Tousethe command linetoolsyouneedto source the file . *ToaccesstheOpenStackDashboardbrowsetohttp: //192 .168.1.201 /dashboard . Please, find yourlogincredentialsstored in thekeystonerc_admin in yourhomedirectory. *TouseNagios,browsetohttp: //192 .168.1.201 /nagios username:nagiosadmin,password:hequan *Theinstallationlog file isavailableat: /var/tmp/packstack/20160704-140637-VHTW2y/openstack-setup .log *Thegeneratedmanifestsareavailableat: /var/tmp/packstack/20160704-140637-VHTW2y/manifests 1 2 3 4 5 6 7 8 [root@h1~] #catkeystonerc_admin unset OS_SERVICE_TOKEN export OS_USERNAME=admin export OS_PASSWORD=hequan export OS_AUTH_URL=http: //192 .168.1.201:5000 /v2 .0 export PS1= '[\u@\h\W(keystone_admin)]\$' export OS_TENANT_NAME=admin export OS_REGION_NAME=RegionOne 登陆后,右上角点击admin 密码hequan 设置语言 时区 添加节点 结算节点: 192.168.1.202 h2.hequan.com h2 同上 配置yum 和openstack软件环境 1 2 [root@h1~] #ssh-keygen [root@h1~] #ssh-copy-id-i.ssh/id_rsa.pubh2 1 2 3 4 vimhe.txt 84 #ListtheserversonwhichtoinstalltheComputeservice. 85CONFIG_COMPUTE_HOSTS=192.168.1.201,192.168.1.202 ##只要在文件里面添加上节点,再次执行就可以了。 packstack--answer- file =he.txt ##再次执行,不会覆盖原来的 本文转自 295631788 51CTO博客,原文链接:http://blog.51cto.com/hequan/1795664,如需转载请自行联系原作者

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

新浪微博布局学习——活用RelativeLayout

正文 一、效果图 格子布局效果: (图一) 居中正在加载的效果: (图二) 二、实现代码 2.1 实现 图一 效果代码 < RelativeLayout android:id ="@id/rlDigest" android:background ="@drawable/panel_bg" android:layout_width ="fill_parent" android:layout_height ="100.0dip" android:layout_margin ="10.0dip" > < TextView android:textSize ="16.0sp" android:textColor ="#ff7d899d" android:gravity ="center_vertical" android:id ="@id/tvAddress" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:layout_marginLeft ="5.0dip" android:layout_marginTop ="10.0dip" android:text ="@string/userinfo_address" android:layout_alignParentLeft ="true" android:layout_alignParentTop ="true" /> < TextView android:textSize ="16.0sp" android:textColor ="#ff373737" android:id ="@id/tvAddress_content" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:layout_marginLeft ="10.0dip" android:layout_toRightOf ="@id/tvAddress" android:layout_alignTop ="@id/tvAddress" /> < View android:id ="@id/vHDivider" android:background ="@drawable/horizontal_separation_line_repeat" android:layout_width ="fill_parent" android:layout_height ="1.0dip" android:layout_centerVertical ="true" /> < TextView android:textSize ="16.0sp" android:textColor ="#ff7d899d" android:gravity ="center_vertical" android:id ="@id/tvAccount_info" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:text ="@string/account_info" android:layout_below ="@id/vHDivider" android:layout_alignLeft ="@id/tvAddress" android:layout_alignParentBottom ="true" /> < TextView android:textSize ="16.0sp" android:textColor ="#ff373737" android:gravity ="center_vertical" android:id ="@id/tvAccount_info_content" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:layout_marginLeft ="10.0dip" android:layout_marginBottom ="12.0dip" android:singleLine ="true" android:layout_toRightOf ="@id/tvAccount_info" android:layout_alignBottom ="@id/tvAccount_info" /> </ RelativeLayout > < RelativeLayout android:background ="@drawable/panel_bg" android:layout_width ="fill_parent" android:layout_height ="130.0dip" android:layout_margin ="10.0dip" > < View android:id ="@id/vVDivider1" android:background ="@drawable/vertical_separation_line_repeat" android:layout_width ="1.0dip" android:layout_height ="fill_parent" android:layout_centerHorizontal ="true" /> < View android:id ="@id/vHDivider2" android:background ="@drawable/horizontal_separation_line_repeat" android:layout_width ="fill_parent" android:layout_height ="1.0dip" android:layout_centerVertical ="true" /> < RelativeLayout android:id ="@id/llAttention" android:background ="@drawable/bg_panel_above_left" android:clickable ="true" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:layout_toLeftOf ="@id/vVDivider1" android:layout_above ="@id/vHDivider2" android:layout_alignParentLeft ="true" android:layout_alignParentTop ="true" > < TextView android:gravity ="center" android:id ="@id/tvAttention_count" android:layout_width ="fill_parent" android:layout_height ="wrap_content" android:layout_marginTop ="10.0dip" android:text ="0" android:layout_centerHorizontal ="true" style ="@style/userinfo_panel_textview_count" /> < TextView android:gravity ="center" android:id ="@id/tvAttention" android:layout_width ="fill_parent" android:layout_height ="wrap_content" android:text ="@string/attention" android:layout_below ="@id/tvAttention_count" android:layout_centerHorizontal ="true" style ="@style/userinfo_panel_textview_title" /> </ RelativeLayout > < LinearLayout android:orientation ="vertical" android:id ="@id/rlWeibo" android:background ="@drawable/bg_panel_above_right" android:clickable ="true" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:layout_toRightOf ="@id/vVDivider1" android:layout_above ="@id/vHDivider2" android:layout_alignParentTop ="true" android:layout_alignParentRight ="true" > < TextView android:gravity ="center" android:layout_gravity ="center_horizontal" android:id ="@id/tvWeibo_count" android:layout_width ="fill_parent" android:layout_height ="wrap_content" android:layout_marginTop ="10.0dip" android:text ="0" style ="@style/userinfo_panel_textview_count" /> < TextView android:gravity ="center" android:layout_gravity ="center_horizontal" android:id ="@id/tvTopic" android:layout_width ="fill_parent" android:layout_height ="wrap_content" android:text ="@string/radio_button_topic" style ="@style/userinfo_panel_textview_title" /> </ LinearLayout > < LinearLayout android:orientation ="vertical" android:id ="@id/llFans" android:background ="@drawable/bg_panel_below_left" android:clickable ="true" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:layout_toLeftOf ="@id/vVDivider1" android:layout_below ="@id/vHDivider2" android:layout_alignParentLeft ="true" android:layout_alignParentBottom ="true" > < TextView android:gravity ="center" android:layout_gravity ="center_horizontal" android:id ="@id/tvFans_count" android:layout_width ="fill_parent" android:layout_height ="wrap_content" android:layout_marginTop ="10.0dip" android:text ="0" style ="@style/userinfo_panel_textview_count" /> < TextView android:gravity ="center" android:layout_gravity ="center_horizontal" android:id ="@id/tvFans" android:layout_width ="fill_parent" android:layout_height ="wrap_content" android:text ="@string/fans" style ="@style/userinfo_panel_textview_title" /> </ LinearLayout > < LinearLayout android:orientation ="vertical" android:id ="@id/llTopic" android:background ="@drawable/bg_panel_below_right" android:clickable ="true" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:layout_toRightOf ="@id/vVDivider1" android:layout_below ="@id/vHDivider2" android:layout_alignParentRight ="true" android:layout_alignParentBottom ="true" > < TextView android:gravity ="center" android:layout_gravity ="center_horizontal" android:id ="@id/tvTopic_count" android:layout_width ="fill_parent" android:layout_height ="wrap_content" android:layout_marginTop ="10.0dip" android:text ="0" style ="@style/userinfo_panel_textview_count" /> < TextView android:gravity ="center" android:layout_gravity ="center_horizontal" android:id ="@id/tvTopic" android:layout_width ="fill_parent" android:layout_height ="wrap_content" android:text ="@string/his_topics" style ="@style/userinfo_panel_textview_title" /> </ LinearLayout > </ RelativeLayout > 代码说明: 2.1.1 第一个RelativeLayout为图一上的实现代码。注意使用了一个View,也就是一条横线,令其居中布局;"地址:"的TextView通过layout_alignParentLeft和layout_alignParentTop令其在整个RelativeLayout顶左顶上;"账号信息:"的TextView通过layout_below令其位于横线下方,layout_alignLeft令其与"地址:"的TextView左边对齐,然后用layout_alignParentBottom让其居于容器底部。 2.1.2 第二个RelativeLayout为图一下的实现代码。关键是vVDivider1和vVDivider2,与3.1.1类似,画出了一个十字架的布局,然后分别用居左、居上、居下、居右等方式实现了该布局效果。 2.2 实现 图二 效果代码 < RelativeLayout android:id ="@+id/rlpb" android:layout_width ="fill_parent" android:background ="#ffeff0f4" android:visibility ="gone" android:layout_height ="fill_parent" android:layout_weight ="1.0" > < LinearLayout android:layout_centerInParent ="true" android:layout_width ="wrap_content" android:layout_height ="wrap_content" > < ProgressBar android:id ="@+id/prb" style ="?android:attr/progressBarStyleSmallTitle" android:layout_width ="wrap_content" android:layout_height ="wrap_content" /> < TextView android:text ="@string/loadinfo" android:layout_width ="wrap_content" android:layout_height ="wrap_content" /> </ LinearLayout > </ RelativeLayout > 代码说明: 主要是layout_centerInParent属性的应用,令其居于RelativeLayout的中间。使用的时候领ListView先隐藏,然后让这个布局显示并填充,用完在设置Visible为GONE即可。 三、总结 熟练掌握以下重要属性,并灵活运用: android:layout_centerInParent 居中布局 android:layout_centerVertical 水平居中布局 android:layout_centerHorizontal 垂直居中布局 android:layout_alignParentTop 居于容器内顶部 android:layout_alignParentBottom 居于容器内底部 android:layout_alignParentLeft 居于容器内左边 android:layout_alignParentRight 居于容器内右边 android:layout_above 居于指定View的上方 android:layout_below 居于指定View的下方 android:layout_toRightOf 在指定View的右边 android:layout_toLeftOf 在指定View的左边 android:layout_alignTop 与指定View的Top一致 本文转自over140 51CTO博客,原文链接:http://blog.51cto.com/over140/582146,如需转载请自行联系原作者

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

Android学习笔记--SQLite使用方法

SQLite介绍 http://www.sqlite.org 官方网站 小型关系数据库 SQLiteOpenHelper使用方法 getReadableDatabase() getWritableDatabase() onCreate(SQLiteDatabasedb) onOpen(SQLiteDatabasedb) onUpgrade(SQLiteDatabsedb,intoldVersion,intnewVersion) Close(); //DatabaseHelper所为一个访问SQLite的助手类,提供两个方面的功能 //第一,getReadableDatabase()和getWritableDatabasr()可以获得SQLiteDatabase对象 //第二,提供onCreate和onUpgrade两个回调函数,允许我们在创建和升级数据库时,进行操作 例:publicclassDatabaseHelperextendsSQLiteOpenHelper{ //数据库版本号 PrivatestaticfinalintVERSION=1; //必须的构造函数 PublicDatabaseHelper(Contextcontext,Stringname,CursorFactoryfactory,intversion){ Super(context,name,factory,version); } PublicDatabaseHelper(Contextcontext,Stringname,intversion){ Super(context,name,null,version); } PublicDatabaseHelper(Contextcontext,Stringname){ Super(context,name,null,VERSION); } PublicvoidonCreate(SQLiteDatabasedb){ System.out.println("createadatabase"); Db.execSQL("createtableuser(idint,namevarchar(20))"); } PublicvoidonUpgrade(SQLiteDatabasedb){ System.out.println("updateadatabase"); } } 对SQLite的增删查改 Activity操作数据库例: 1.声明控件对象(略) 2.获得控件对象(略) 3.绑定事件(略) 4.创建监听器对象(调用DatabaseHelper) //创建一个数据库 PublicvoidonClick(Viewv){ //当前的activity,还有数据名 DatabaseHelperdbHelper=newDatabaseHelper(SQLiteActivity.this,"test_db"); SQLiteDatabasedb=dbHelper.getReadableDatabase();//此时才会创建一个数据库 } //修改一个数据库 PublicvoidonClick(Viewv){ //当前的activity,还有数据名 DatabaseHelperdbHelper=newDatabaseHelper(SQLiteActivity.this,"test_db",2);//版本号变了 SQLiteDatabasedb=dbHelper.getReadableDatabase(); } //插入操作 PublicvoidonClick(Viewv){ //生成ContentValues对象 ContentValuesvalues=newContentValues(); //key是列名,value是值,值必须对应数据库列数据类型 Values.put("id",1); Values.put("name","zhangsan"); //当前的activity,还有数据名 DatabaseHelperdbHelper=newDatabaseHelper(SQLiteActivity.this,"test_db"); //得到可写数据库 SQLiteDatabasedb=dbHelper.getWritableDatabase(); //1.表名2,不允许空列3,值 Db.insert("user",null,values); } //更新操作 PublicvoidonClick(Viewv){ //当前的activity,还有数据名 DatabaseHelperdbHelper=newDatabaseHelper(SQLiteActivity.this,"test_db"); //得到可写数据库 SQLiteDatabasedb=dbHelper.getWritableDatabase(); //1.表名2,不允许空列3,值 //生成ContentValues对象 ContentValuesvalues=newContentValues(); //key是列名,value是值,值必须对应数据库列数据类型 Values.put("name","zhangsanfeng"); //1.表名2.值,3,where子句(不包括where)4,为占位符赋值 Db.update("user",values,"id=?",newString[]{"1"}); } //查询数据库 PublicvoidonClick(Viewv){ //当前的activity,还有数据名 DatabaseHelperdbHelper=newDatabaseHelper(SQLiteActivity.this,"test_db");//版本号变了 SQLiteDatabasedb=dbHelper.getReadableDatabase(); //1,表名2所要查询的列名3,筛选器4,筛选器值5.groupby6.having //7orderby创建游标对象读取数据 Cursorcursor=db.query("user","newString[]{"id","name"}","id=?") While(cursor.moveToNext()){ Stringname=cursor.getString(cursor.getColumnIndex("name")); System.out.println("query--->"+name); } } //删除操作 PublicvoidonClick(Viewv){ //当前的activity,还有数据名 DatabaseHelperdbHelper=newDatabaseHelper(SQLiteActivity.this,"test_db"); //得到可写数据库 SQLiteDatabasedb=dbHelper.getWritableDatabase(); //1.表名2.值,3,where子句(不包括where)4,为占位符赋值 Db.delete("user",values,"id=?",newString[]{"1"}); } 使用adb访问SQLite(linux命令行调试)abdshell=>ls-i=>cddata=>创建了数据库之后=>报名.数据库名=>即可进入该SQLite SQLite语句.schema//查看所有表 Linux知识补习:cd目录(进入目录)ls(查看当前目录) 本文转自My_King1 51CTO博客,原文链接:http://blog.51cto.com/apprentice/1360571,如需转载请自行联系原作者

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

PHPUnit学习02---如何管理TestCase

本文目的 本文介绍了phpunit通用函数用法,整体架构,和如何使用TestSuite来管理项目的所有的测试用例。 批量运行 当配置好phpunit后,可以使用“phpunit someTestCase”命令执行单个用例,使得用例的执行很方便。但是如果testcase分散到多个文件中,一个一个的执行phpunit就变得很麻烦了。好在,phpunit命令提供了一些可选参数,可以使得批量处理Test Case变得容易,可以直接执行phpunit查看这些可选参数,如下所示: 上图中,红圈标注的地方就是用于批量运行测试用例的参数,同时,phpunit也可以默认的执行指定目录下*Test.php文件中的测试用例,并且是迭代的遍历所有子目录,如下面的例子: 在test/UnitTestDemo目录下面四个文件,只有两个文件是以*Test.php格式结尾,所以运行“phpunit test”命令可以批量的运行这些符合要求的用例。如果你希望更细粒度的控制执行特定用例,可以使用“--filter”参数,该参数通过过滤用例文件名称来执行特定文件中的测试用例。 命名约定 PHPUnit中默认的命令规则,可以使得运行测试用例变得十分方便。列举如下: 自动执行每个TestCase类中test***形式的方法 自动执行目录下*Test.php形式命名中的用例 一旦遵守了这些命名约定,编写单元测试将会更加便捷。 setUp和tearDown setUp和tearDown可以帮助我们搭建和清理测试环境,TestCase和TestSuite两个类均有这对函数,可以共用户重载。但是,需要注意这两对函数调用的时机不一样,在TestCase中,每一次test***方法调用前均会调用setUp方法,调用后均会调用tearDown方法。但是,在TestSuite中,只会在第一个testCase调用之前调用setup,最后一个testCase调用后,调用tearDown。可以通过下面的例子,了解整个调用过程。 代码如下: MySuite.php 1 2 3 4 5 6 7 <?php require_once 'MyTest.php' ; class MySuite extends PHPUnit_Framework_TestSuite { public static function suite() { 1 2 3 4 5 6 7 8 9 10 11 12 13 return new MySuite( 'MyTest' ); } protected function setUp() { print "\nMySuite::setUp()" ; } protected function tearDown() { print "\nMySuite::tearDown()" ; } } ?> MyTest.php 1 2 3 4 5 6 7 <?php class MyTest extends PHPUnit_Framework_TestCase { protected function setUp() { print "\nMyTest::setUp()" ; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 protected function tearDown() { print "\nMyTest::tearDown()" ; } public function testOne() { print "\nMyTest::testOne()" ; } public function testTwo() { print "\nMyTest::testTwo()" ; } } ?> PHPUnit系统架构 上图展示的PHPUnit库的架构,看起来是不是似曾相识?如果你了解设计模式,应该不难发现PHPUnit的整体架构采用的“组合设计模式”,定义如下: (组合设计模式将对象以树形结构组织起来,以达成“部分-整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性.组合设计模式比较容易理解,它就是一个树形结构图。组合体内这些对象都有共同接口,当组合体一个对象的方法被调用执行时,组合设计模式将遍历整个树形结构,寻找同样包含这个方法的对象并实现调用执行。可以用牵一动百来形容。组合设计模式好处:1.使客户端调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不必关心自己处理的是单个对象还是整个组合结构,这就简化了客户端代码。2.更容易在组合体内加入对象部件. 客户端不必因为加入了新的对象部件而更改代码。) 注意:为了简洁,描述上图对象时,均省略掉“PHPUnit2_Framework_”前缀。所以,使用Test作为统一的接口, TestCase是测试用用例,继承于Assert,这样可以方便的调用Assert中的各种断言函数。TestSuite,是一个Test的集合,他可以包含任意的TestCase或TestSuite。这样设计的好处不言而喻——方便的组织测试用例和测试套件,客户代码不必关执行的是单个测试用例还是一整套测试套件或是更为复杂的测试用例树。 使用testsuite管理所有测试用例 有了上面的知识,现在就可以使用TestSuite对象管理和组织你的测试用例了。我们有如下四个测试用例需要组织: 希望将Stack相关的测试一起运行,其他用例一起运行,并且在需要时,所有的用例可以全部运行,那么就创建如下三个测试套件对象。 上面的测试套件只添加Stack相关的测试,运行结果如下: 上面的测试套件只添加其他测试用例,运行结果如下: 如果希望运行所有的套件,可以使用上面的测试套件进行组织,运行结果如下: 通过上面代码中画圈的部分,可以发现一些共性: 1) 测试套件类集成与PHPUnit_Framework_TestSuite类; 2) 测试套件类必须实现public static function suite(){/*必须返回测试套件对象*/}接口; 3) 通过addTestSuite(‘Test Case Class Name’),将具体的测试用例添加到测试套件中。 如果在真实的项目中,可以以模块为单位组织测试套件。如过模块过大,可以在模块内部继续划分测试套件,这样,形成一个树装结构,需要运行那部分测试用例,只需要敲入一行命令“phpunit XXXXTestSuite.php”,就可以轻松执行(上面的代码见附件)。合理的使用测试套件,可以简洁有效的组织所有测试用例。 参考文献 PHPUnit官方手册http://www.phpunit.de/manual/3.4/en/organizing-tests.html 组合设计模式http://www.jdon.com/designpatterns/composite.htm 声明:如有转载本博文章,请注明出处。您的支持是我的动力!文章部分内容来自互联网,本人不负任何法律责任。 本文转自bourneli博客园博客,原文链接:http://www.cnblogs.com/bourneli/archive/2012/04/27/2474005.html ,如需转载请自行联系原作者

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

Android Bitmap和Canvas学习笔记 [转]

原文:http://www.cnblogs.com/feisky/archive/2010/01/10/1643460.html 位图是我们开发中最常用的资源,毕竟一个漂亮的界面对用户是最有吸引力的。 1. 从资源中获取位图 可以使用BitmapDrawable或者BitmapFactory来获取资源中的位图。 当然,首先需要获取资源: Resources res=getResources(); 使用BitmapDrawable获取位图 使用BitmapDrawable (InputStream is)构造一个BitmapDrawable; 使用BitmapDrawable类的getBitmap()获取得到位图; // 读取InputStream并得到位图 InputStream is=res.openRawResource(R.drawable.pic180); BitmapDrawable bmpDraw=new BitmapDrawable(is); Bitmap bmp=bmpDraw.getBitmap(); 或者采用下面的方式: BitmapDrawable bmpDraw=(BitmapDrawable)res.getDrawable(R.drawable.pic180); Bitmap bmp=bmpDraw.getBitmap(); 使用BitmapFactory获取位图 (Creates Bitmap objects from various sources, including files, streams, and byte-arrays.) 使用BitmapFactory类decodeStream(InputStream is)解码位图资源,获取位图。 Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.pic180); BitmapFactory的所有函数都是static,这个辅助类可以通过资源ID、路径、文件、数据流等方式来获取位图。 以上方法在编程的时候可以自由选择,在Android SDK中说明可以支持的图片格式如下:png (preferred), jpg (acceptable), gif (discouraged),和bmp(Android SDK Support Media Format)。 2. 获取位图的信息 要获取位图信息,比如位图大小、像素、density、透明度、颜色格式等,获取得到Bitmap就迎刃而解了,这些信息在Bitmap的手册中,这里只是辅助说明以下2点: 在Bitmap中对RGB颜色格式使用Bitmap.Config定义,仅包括ALPHA_8、ARGB_4444、ARGB_8888、RGB_565,缺少了一些其他的,比如说RGB_555,在开发中可能需要注意这个小问题; Bitmap还提供了compress()接口来压缩图片,不过AndroidSAK只支持PNG、JPG格式的压缩;其他格式的需要Android开发人员自己补充了。 3. 显示位图 显示位图可以使用核心类Canvas,通过Canvas类的drawBirmap()显示位图,或者借助于BitmapDrawable来将Bitmap绘制到Canvas。当然,也可以通过BitmapDrawable将位图显示到View中。 转换为BitmapDrawable对象显示位图 // 获取位图 Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.pic180); // 转换为BitmapDrawable对象 BitmapDrawable bmpDraw=newBitmapDrawable(bmp); // 显示位图 ImageView iv2 = (ImageView)findViewById(R.id.ImageView02); iv2.setImageDrawable(bmpDraw); 使用Canvas类显示位图 这儿采用一个继承自View的子类Panel,在子类的OnDraw中显示 public class MainActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new Panel(this)); } class Panel extends View{ public Panel(Context context) { super(context); } public void onDraw(Canvas canvas){ Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.pic180); canvas.drawColor(Color.BLACK); canvas.drawBitmap(bmp, 10, 10, null); } } } 4. 位图缩放 (1)将一个位图按照需求重画一遍,画后的位图就是我们需要的了,与位图的显示几乎一样:drawBitmap(Bitmapbitmap,Rectsrc,Rectdst,Paintpaint)。 (2)在原有位图的基础上,缩放原位图,创建一个新的位图:CreateBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter) (3)借助Canvas的scale(float sx, float sy) (Preconcat the current matrix with the specified scale.),不过要注意此时整个画布都缩放了。 (4)借助Matrix: Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.pic180); Matrix matrix=new Matrix(); matrix.postScale(0.2f, 0.2f); Bitmap dstbmp=Bitmap.createBitmap(bmp,0,0,bmp.getWidth(), bmp.getHeight(),matrix,true); canvas.drawColor(Color.BLACK); canvas.drawBitmap(dstbmp, 10, 10, null); 5. 位图旋转 同样,位图的旋转也可以借助Matrix或者Canvas来实现。 Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.pic180); Matrix matrix=new Matrix(); matrix.postScale(0.8f, 0.8f); matrix.postRotate(45); Bitmap dstbmp=Bitmap.createBitmap(bmp,0,0,bmp.getWidth(), bmp.getHeight(),matrix,true); canvas.drawColor(Color.BLACK); canvas.drawBitmap(dstbmp, 10, 10, null); 旋转效果: 6.图片水印的生成方法 生成水印的过程。其实分为三个环节:第一,载入原始图片;第二,载入水印图片;第三,保存新的图片。 /** * create thebitmapfrom a byte array * * @param src thebitmapobject you want proecss * @param watermark the water mark above the src * @return return abitmapobject ,if paramter's length is 0,return null */ privateBitmap createBitmap( Bitmap src, Bitmap watermark ) { String tag ="createBitmap"; Log.d( tag,"create a newbitmap"); if( src ==null) { returnnull; } intw = src.getWidth(); inth = src.getHeight(); intww = watermark.getWidth(); intwh = watermark.getHeight(); //create the new blankbitmap Bitmap newb = Bitmap.createBitmap( w, h, Config.ARGB_8888 );//创建一个新的和SRC长度宽度一样的位图 Canvas cv =newCanvas( newb ); //draw src into cv.drawBitmap( src,0,0,null);//在 0,0坐标开始画入src //draw watermark into cv.drawBitmap( watermark, w - ww +5, h - wh +5,null);//在src的右下角画入水印 //save all clip cv.save( Canvas.ALL_SAVE_FLAG );//保存 //store cv.restore();//存储 returnnewb; } 7.Canvas的save和restore onDraw方法会传入一个Canvas对象,它是你用来绘制控件视觉界面的画布。 在onDraw方法里,我们经常会看到调用save和restore方法,它们到底是干什么用的呢? save:用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。 restore:用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。 save和restore要配对使用(restore可以比save少,但不能多),如果restore调用次数比save多,会引发Error。save和restore之间,往往夹杂的是对Canvas的特殊操作。 例如:我们先想在画布上绘制一个右向的三角箭头,当然,我们可以直接绘制,另外,我们也可以先把画布旋转90°,画一个向上的箭头,然后再旋转回来(这种旋转操作对于画圆周上的标记非常有用)。然后,我们想在右下角有个20像素的圆,那么,onDraw中的核心代码是: int px = getMeasuredWidth(); int py = getMeasuredWidth(); // Draw background canvas.drawRect(0, 0, px, py, backgroundPaint); canvas.save(); canvas.rotate(90, px/2, py/2); // Draw up arrow canvas.drawLine(px / 2, 0, 0, py / 2, linePaint); canvas.drawLine(px / 2, 0, px, py / 2, linePaint); canvas.drawLine(px / 2, 0, px / 2, py, linePaint); canvas.restore(); // Draw circle canvas.drawCircle(px - 10, py - 10, 10, linePaint); 效果如图1所示: 如果我们不调用save和restore会是什么样子呢?如图2所示: 从这两个图中,我们就能看到圆圈位置的明显差异。不进行Canvas的save和restore操作的话,所有的图像都是在画布旋转90°后的画布上绘制的。当执行完onDraw方法,系统自动将画布恢复回来。save和restore操作执行的时机不同,就能造成绘制的图形不同。 本文参考: Android SDK moandroid.com http://www.cnblogs.com/xirihanlin/archive/2009/07/24/1530246.html 本文转自Work Hard Work Smart博客园博客,原文链接:http://www.cnblogs.com/linlf03/p/3582003.html,如需转载请自行联系原作者

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

学习身份证图像识别

前言: 实名认证是互联网的大趋势.越来越多的地方需要用户实名认证了.我目前所在的公司网站也有这个需求.可是公司之前一直使用的是人工后台审核.这样做有几个不好的地方 绝大多数用户还是会上传真实有效的身份信息,所以审查结果往往都是通过 用户在上传后认证需要等待,可是等待的过程往往就是失去用户的过程. 加大了我们网站工作人员的工作量,不利于后期发展 通过分析这些问题.我决定使用百度的人工智能提供的接口,来完成智能实名认证. 目录: 申请应用 获取accessToken 调用识别接口,获取数据 对比数据 业务逻辑介绍 1. 申请应用 image.png 在百度云的控制台中找到,人工智能部分,选择你需要的服务 image.png 然后创建你需要的应用,创建好了就可以获得app_key 和app_secret(好像不叫这个名字,不过是什么东西.大家都懂) 看到这两个熟悉的东西.大家一定会想到第三方登录是吧.没错这里的应用也是基于Oauth2.0协议.比较关注我的朋友应该看过,我之前写的关于第三方登录的博客.这里就过多介绍原理了.直接讲用法 2. 获取access_token 拿到app_key和app_secret这两个参数之后,我们就可以来获取access_token了. 和其他Oauth2.0协议的应用相同,都是用curl的方式去请求这个token class BaiduAiController extends Controller { //公共的成员变量 public $accessToken; /** * 在类成员变量中没有accessToken,或者accessToken过期则调这个方法 */ public function getAccessToken() { //获取配置参数 $config=C('BAIDUAI'); //百度ai的token请求地址 $url='https://aip.baidubce.com/oauth/2.0/token'; $post_data = []; //这个是参数是固定写法 $post_data['grant_type'] = 'client_credentials'; //依次填入我们在配置中设置好的参数 $post_data['client_id'] = $config['app_id']; $post_data['client_secret'] = $config['app_secret']; //调用公共的curl方法,第一个参数是url,第二个参数是请求类型,第三个参数是携带的数据 $result=http($url,'POST',$post_data); //状态无误 if ($result[0]==200) { //将返回的json数据转换为数组,并取出token存入类成员变量中 $this->accessToken=json_decode($result[1],true)['access_token']; //返回token return $this->accessToken; } } } 我将获取token单独写了一个控制器,其实也可以不用写,看个人习惯.通过这个方法,我们就能获取到token,用于我们调用其它接口 3.调用识别身份证照片的接口 百度身份证识别可以识别身份证的正面,背面上面的文字.也就是说可以获取到用户的姓名,性别,生日,住址,身份证号,发证机关,有效期. 调用接口,需要传入的数据有 base64加密后的二进制的图片流 //没懂没关系,我们看代码 //获取图片的2进制流$imgUrl是图片的url $img = file_get_contents($imgUrl); //将字符串进行base64加密 $img = base64_encode($img); 传入图片的正面或则背面的信息 其实就是你要检测正面就传入正面参数,背面就传入背面参数 当前还有更多更高级的应用,需要传入其他数据.由于本次应用没有用到,就不展开了说了 image.png 下面看完整的代码 /** * 调用身份证识别接口,返回识别后的数据 * @param $imgUrl * @return array */ private function checkID($imgUrl) { //实例化baiduai控制器对象 $baiduObj = new BaiduAiController(); //获取到accesstoken $accessToken = isset($baiduObj->accessToken) ? $baiduObj->accessToken : $baiduObj->getAccessToken(); $url = 'https://aip.baidubce.com/rest/2.0/ocr/v1/idcard?access_token=' . $accessToken; //获取图片的2进制流$imgUrl是图片的url $img = file_get_contents($imgUrl); //将字符串进行base64加密 $img = base64_encode($img); $bodys = array( //这个代表的是,识别身份证的正面 'id_card_side' => 'front', "image" => $img ); //使用curl方法 获取接口返回的数据 $res = http($url, 'POST', $bodys); //访问状态没问题 if ($res[0] == 200) { //access过期 if (isset($res[1]['error_code'])==11) { //重新赋值,递归,返回数据 $baiduObj->accessToken=null; return $this->checkID($imgUrl); } //将返回的数据,转换为数组 $res = json_decode($res[1], true); //提取数组中的身份证号码 $ID = $res['words_result']['公民身份号码']['words']; //提取数组中的姓名 $realname = $res['words_result']['姓名']['words']; $result = []; //在两个数据都识别出的情况下,存入返回数组 if (isset($ID) && isset($realname)) { $result['status'] = 1; $result['ID'] = $ID; $result['realname'] = $realname; } else { //没有获取到完整数据,返回状态码 $result['status'] = 0; } //返回数据 return $result; } } 下面是返回数据的示例,每个参数的定义,欢迎查看官方手册 { "log_id": 2648325511,//唯一id,方便定位错误 "direction": 0, "image_status": "normal", "idcard_type": "normal", "edit_tool": "Adobe Photoshop CS3 Windows", "words_result": { "住址": { "location": { "left": 267, "top": 453, "width": 459, "height": 99 }, "words": "南京市江宁区弘景大道3889号" }, "公民身份号码": { "location": { "left": 443, "top": 681, "width": 589, "height": 45 }, "words": "330881199904173914" }, "出生": { "location": { "left": 270, "top": 355, "width": 357, "height": 45 }, "words": "19990417" }, "姓名": { "location": { "left": 267, "top": 176, "width": 152, "height": 50 }, "words": "伍云龙" }, "性别": { "location": { "left": 269, "top": 262, "width": 33, "height": 52 }, "words": "男" }, "民族": { "location": { "left": 492, "top": 279, "width": 30, "height": 37 }, "words": "汉" } }, "words_result_num": 6 } 4. 对比识别出的数据和 用户的输入的数据是否一致 这个就太简单了 就不过多介绍了 /** * 对比识别出的数据,和用户填写的数据是否一致 * @param $idData * @param $userData * @return bool */ private function comparisonID($idData, $userData) { if ($idData['realname'] == $userData['realname'] && $idData['ID'] == $userData['ID']) { return true; } else { return false; } } 注意,返回的数据,并不只有身份证号和姓名.大家可以按照自己的需求来获取数据.还有就是那个acess_token过期部分,并没有验证.希望大神指正 5.下面介绍下我所经手的网站的业务流程 自动认证身份证.png 注意:这个接口并非免费使用,每日免费500次调用.对于我现在所经手的网站那是搓搓有余了.具体价格感兴趣的朋友的到官网了解 好了,本次身份证图像识别的介绍了就写到这里了,如果有什么地方不对,希望大神指正.谢谢

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

Docker容器学习梳理--日常操作总结

使用Docker已有一段时间了,今天正好有空梳理下自己平时操作Docker时的一些命令和注意细节: Docker 命令帮助 $ sudo docker Commands: attach Attach to a running container --将终端依附到容器上 1> 运行一个交互型容器 [root@localhost ~]# docker run -i -t centos /bin/bash [root@f0a02b473067 /]# 2> 在另一个窗口上查看该容器的状态 [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d4a75f165ce6 centos "/bin/bash" 5 seconds ago Up 5 seconds cranky_mahavira 3> 退出第一步中运行的容器 [root@d4a75f165ce6 /]# exit exit 4> 查看该容器的状态 [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d4a75f165ce6 centos "/bin/bash" 2 minutes ago Exited (0) 23 seconds ago cranky_mahavira 可见此时容器的状态是Exited,那么,如何再次运行这个容器呢?可以使用docker start命令 5> 再次运行该容器 [root@localhost ~]# docker start cranky_mahavira cranky_mahavira 6> 再次查看该容器的状态 [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d4a75f165ce6 centos "/bin/bash" 6 minutes ago Up 29 seconds cranky_mahavira 因为该容器是交互型的,但此刻我们发现没有具体的终端可以与之交互,这时可使用attach命令。 7> 通过attach命令进行交互 [root@localhost ~]# docker attach cranky_mahavira [root@d4a75f165ce6 /]# build Build an image from a Dockerfile --通过Dockerfile创建镜像 commit Create a new image from a container's changes --通过容器创建本地镜像 注意:如果是要push到docker hub中,注意生成镜像的命名 [root@localhost ~]# docker commit centos_v1 centos:v1 68ad49c999496cff25fdda58f0521530a143d3884e61bce7ada09bdc22337638 [root@localhost ~]# docker push centos:v1 You cannot push a "root" repository. Please rename your repository to <user>/<repo> (ex: <user>/centos) 用centos:v1就不行,因为它push到docker hub中时,是推送到相应用户下,必须指定用户名。譬如我的用户名是ivictor,则新生成的本地镜像命名为: docker push victor/centos:v1,其中v1是tag,可不写,默认是latest cp Copy files/folders from a container to a HOSTDIR or to STDOUT --在宿主机和容器之间相互COPY文件 cp的用法如下: Usage: docker cp [OPTIONS] CONTAINER:PATH LOCALPATH|- docker cp [OPTIONS] LOCALPATH|- CONTAINER:PATH 如:容器mysql中/usr/local/bin/存在docker-entrypoint.sh文件,可如下方式copy到宿主机 # docker cp mysql:/usr/local/bin/docker-entrypoint.sh /root 修改完毕后,将该文件重新copy回容器 # docker cp /root/docker-entrypoint.sh mysql:/usr/local/bin/ create Create a new container --创建一个新的容器,注意,此时,容器的status只是Created diff Inspect changes on a container's filesystem --查看容器内发生改变的文件,以我的mysql容器为例 [root@localhost ~]# docker diff mysqldb C /root A /root/.bash_history A /test1.txt A /test.tar A /test.txt C /run C /run/mysqld A /run/mysqld/mysqld.pid A /run/mysqld/mysqld.sock 不难看出,C对应的均是目录,A对应的均是文件 events Get real time events from the server --实时输出Docker服务器端的事件,包括容器的创建,启动,关闭等。 譬如: [root@localhost ~]# docker events 2015-09-08T17:40:13.000000000+08:00 d2a2ef5ddb90b505acaf6b59ab43eecf7eddbd3e71f36572436c34dc0763db79: (from wordpress) create 2015-09-08T17:40:14.000000000+08:00 d2a2ef5ddb90b505acaf6b59ab43eecf7eddbd3e71f36572436c34dc0763db79: (from wordpress) die 2015-09-08T17:42:10.000000000+08:00 839866a338db6dd626fa8eabeef53a839e4d2e2eb16ebd89679aa722c4caa5f7: (from mysql) start exec Run a command in a running container --用于容器启动之后,执行其它的任务 通过exec命令可以创建两种任务:后台型任务和交互型任务 后台型任务:docker exec -d cc touch 123 其中cc是容器名 交互型任务: [root@localhost ~]# docker exec -i -t cc /bin/bash root@1e5bb46d801b:/# ls 123 bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var export Export a container's filesystem as a tar archive --将容器的文件系统打包成tar文件 有两种方式(mysqldb为容器名): docker export -o mysqldb1.tar mysqldb docker export mysqldb > mysqldb.tar history Show the history of an image --显示镜像制作的过程,相当于dockfile images List images --列出本机的所有镜像 import Import the contents from a tarball to create a filesystem image --根据tar文件的内容新建一个镜像,与之前的export命令相对应 [root@localhost ~]# docker import mysqldb.tar mysql:v1 eb81de183cd94fd6f0231de4ff29969db822afd3a25841d2dc9cf3562d135a10 [root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE mysql v1 eb81de183cd9 21 seconds ago 281.9 MB 譬如下面一例: [root@localhost volume2]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9cb07559cc17 docker.io/ubuntu "/bin/bash" 22 hours ago Up 22 hours naughty_bartik [root@localhost volume2]#docker exportgigantic_goldwasser> wanghui.tar [root@localhost volume2]#docker import wanghui.tar wanghui:v1 sha256:b6cbbaf69a58149f337dcc439a21ed185dcdf96fd7f72ddf45e102d27f47c4ae [root@localhost volume2]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE wanghui v1 b6cbbaf69a58 5 seconds ago 450.9 MB [root@localhost volume2]#docker run -i -twanghui:v1/bin/bash [root@78f4ac39972d /]# ps -ef info Display system-wide information --查看docker的系统信息 [root@localhost ~]# docker info Containers: 3 --当前有3个容器 Images: 298 Storage Driver: devicemapper Pool Name: docker-253:0-34402623-pool Pool Blocksize: 65.54 kB Backing Filesystem: xfs Data file: /dev/loop0 Metadata file: /dev/loop1 Data Space Used: 8.677 GB --对应的是下面Data loop file大小 Data Space Total: 107.4 GB Data Space Available: 5.737 GB Metadata Space Used: 13.4 MB --对应的是下面Metadata loop file大小 Metadata Space Total: 2.147 GB Metadata Space Available: 2.134 GB Udev Sync Supported: true Deferred Removal Enabled: false Data loop file: /var/lib/docker/devicemapper/devicemapper/data Metadata loop file: /var/lib/docker/devicemapper/devicemapper/metadata Library Version: 1.02.93-RHEL7 (2015-01-28) Execution Driver: native-0.2 Logging Driver: json-file Kernel Version: 3.10.0-229.el7.x86_64 Operating System: CentOS Linux 7 (Core) CPUs: 2 Total Memory: 979.7 MiB Name: localhost.localdomain ID: TFVB:BXGQ:VVOC:K2DJ:LECE:2HNK:23B2:LEVF:P3IQ:L7D5:NG2V:UKNL WARNING: bridge-nf-call-iptables is disabled WARNING: bridge-nf-call-ip6tables is disabled inspect Return low-level information on a container or image --用于查看容器的配置信息,包含容器名、环境变量、运行命令、主机配置、网络配置和数据卷配置等。 kill Kill a running container --强制终止容器 关于stop和kill的区别,docker stop命令给容器中的进程发送SIGTERM信号,默认行为是会导致容器退出,当然, 容器内程序可以捕获该信号并自行处理,例如可以选择忽略。而docker kill则是给容器的进程发送SIGKILL信号,该信号将会使容器必然退出。 load Load an image from a tar archive or STDIN --与下面的save命令相对应,将下面sava命令打包的镜像通过load命令导入 login Register or log in to a Docker registry --登录到自己的Docker register,需有Docker Hub的注册账号 [root@localhost ~]# docker login Username: ivictor Password: Email: xxxx@foxmail.com WARNING: login credentials saved in /root/.docker/config.json Login Succeeded logout Log out from a Docker registry --退出登录 [root@localhost ~]# docker logout Remove login credentials for https://index.docker.io/v1/ logs Fetch the logs of a container --用于查看容器的日志,它将输出到标准输出的数据作为日志输出到docker logs命令的终端上。常用于后台型容器 pause Pause all processes within a container --暂停容器内的所有进程, 此时,通过docker stats可以观察到此时的资源使用情况是固定不变的, 通过docker logs -f也观察不到日志的进一步输出。 port List port mappings or a specific mapping for the CONTAINER --输出容器端口与宿主机端口的映射情况 譬如: [root@localhost ~]# docker port blog 80/tcp -> 0.0.0.0:80 容器blog的内部端口80映射到宿主机的80端口,这样可通过宿主机的80端口查看容器blog提供的服务 ps List containers --列出所有容器,其中docker ps用于查看正在运行的容器,ps -a则用于查看所有容器。 pull Pull an image or a repository from a registry --从docker hub中下载镜像 push Push an image or a repository to a registry --将本地的镜像上传到docker hub中 前提是你要先用docker login登录上,不然会报以下错误 [root@localhost ~]# docker push ivictor/centos:v1 The push refers to a repository [docker.io/ivictor/centos] (len: 1) unauthorized: access to the requested resource is not authorized rename Rename a container --更改容器的名字 restart Restart a running container --重启容器 rm Remove one or more containers --删除容器,注意,不可以删除一个运行中的容器,必须先用docker stop或docker kill使其停止。 当然可以强制删除,必须加-f参数 如果要一次性删除所有容器,可使用 docker rm -f `docker ps -a -q`,其中,-q指的是只列出容器的ID rmi Remove one or more images --删除镜像 run Run a command in a new container --让创建的容器立刻进入运行状态,该命令等同于docker create创建容器后再使用docker start启动容器 save Save an image(s) to a tar archive --将镜像打包,与上面的load命令相对应 譬如: docker save -o nginx.tar nginx search Search the Docker Hub for images --从Docker Hub中搜索镜像 start Start one or more stopped containers --启动容器 stats Display a live stream of container(s) resource usage statistics --动态显示容器的资源消耗情况,包括:CPU、内存、网络I/O stop Stop a running container --停止一个运行的容器 tag Tag an image into a repository --对镜像进行重命名 top Display the running processes of a container --查看容器中正在运行的进程 unpause Unpause all processes within a container --恢复容器内暂停的进程,与pause参数相对应 version Show the Docker version information --查看docker的版本 wait Block until a container stops, then print its exit code --捕捉容器停止时的退出码 执行此命令后,该命令会“hang”在当前终端,直到容器停止,此时,会打印出容器的退出码。 Docker option 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 Usage of docker: --api- enable -cors= false Enable CORS headers in the remote API # 远程 API 中开启 CORS 头 -b, --bridge= "" Attach containers to a pre-existing network bridge # 桥接网络 use 'none' to disable container networking --bip= "" Use this CIDR notation address for the network bridge's IP, not compatible with -b # 和 -b 选项不兼容,具体没有测试过 -d, --daemon= false Enable daemon mode # daemon 模式 -D, --debug= false Enable debug mode # debug 模式 --dns=[] Force docker to use specific DNS servers # 强制 docker 使用指定 dns 服务器 --dns-search=[] Force Docker to use specific DNS search domains # 强制 docker 使用指定 dns 搜索域 -e, -- exec -driver= "native" Force the docker runtime to use a specific exec driver # 强制 docker 运行时使用指定执行驱动器 --fixed-cidr= "" IPv4 subnet for fixed IPs (ex: 10.20.0.0 /16 ) this subnet must be nested in the bridge subnet ( which is defined by -b or --bip) -G, --group= "docker" Group to assign the unix socket specified by -H when running in daemon mode use '' (the empty string) to disable setting of a group -g, --graph= "/var/lib/docker" Path to use as the root of the docker runtime # 容器运行的根目录路径 -H, --host=[] The socket(s) to bind to in daemon mode # daemon 模式下 docker 指定绑定方式[tcp or 本地 socket] specified using one or more tcp: //host :port, unix: ///path/to/socket , fd: // * or fd: //socketfd . --icc= true Enable inter-container communication # 跨容器通信 --insecure-registry=[] Enable insecure communication with specified registries (no certificate verification for HTTPS and enable HTTP fallback) (e.g., localhost:5000 or 10.20.0.0 /16 ) --ip= "0.0.0.0" Default IP address to use when binding container ports # 指定监听地址,默认所有 ip --ip-forward= true Enable net.ipv4.ip_forward # 开启转发 --ip-masq= true Enable IP masquerading for bridge's IP range --iptables= true Enable Docker's addition of iptables rules # 添加对应 iptables 规则 --mtu=0 Set the containers network MTU # 设置网络 mtu if no value is provided: default to the default route MTU or 1500 if no default route is available -p, --pidfile= "/var/run/docker.pid" Path to use for daemon PID file # 指定 pid 文件位置 --registry-mirror=[] Specify a preferred Docker registry mirror -s, --storage-driver= "" Force the docker runtime to use a specific storage driver # 强制 docker 运行时使用指定存储驱动 --selinux-enabled= false Enable selinux support # 开启 selinux 支持 --storage-opt=[] Set storage driver options # 设置存储驱动选项 --tls= false Use TLS; implied by tls-verify flags # 开启 tls --tlscacert= "/root/.docker/ca.pem" Trust only remotes providing a certificate signed by the CA given here --tlscert= "/root/.docker/cert.pem" Path to TLS certificate file # tls 证书文件位置 --tlskey= "/root/.docker/key.pem" Path to TLS key file # tls key 文件位置 --tlsverify= false Use TLS and verify the remote (daemon: verify client, client: verify daemon) # 使用 tls 并确认远程控制主机 - v , --version= false Print version information and quit Docker run指令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 [root@localhost ~] # docker run --help : docker run [OPTIONS] IMAGE [COMMAND] [ARG...] Run a command in a new container -a, --attach=[] Attach to STDIN, STDOUT or STDERR --add-host=[] Add a custom host-to-IP mapping (host:ip) 增加一个定制的 '主机-IP' 映射 --blkio-weight=0 Block IO (relative weight), between 10 and 1000 -c, --cpu-shares=0 CPU shares (relative weight) --cap-add=[] Add Linux capabilities 增加linux能力 --cap-drop=[] Drop Linux capabilities --cgroup-parent= Optional parent cgroup for the container --cidfile= Write the container ID to the file 把容器的ID写入文件 --cpu-period=0 Limit CPU CFS (Completely Fair Scheduler) period --cpu- quota =0 Limit the CPU CFS quota --cpuset-cpus= CPUs in which to allow execution (0-3, 0,1) --cpuset-mems= MEMs in which to allow execution (0-3, 0,1) -d, --detach= false Run container in background and print container ID 在后台运行容器并打印容器ID --device=[] Add a host device to the container 把一个主机设备添加到容器 --dns=[] Set custom DNS servers 设置定制的域名服务器 --dns-search=[] Set custom DNS search domains 设置定制的域名服务器的搜索域 -e, -- env =[] Set environment variables 设置环境变量 --entrypoint= Overwrite the default ENTRYPOINT of the image 覆盖镜像的默认进入点 -- env - file =[] Read in a file of environment variables 读入一个包含环境变量的文件 --expose=[] Expose a port or a range of ports 暴露一个端口、端口范围 -h, -- hostname = Container host name 容器的主机名 -i, --interactive= false Keep STDIN 标准输入 --ipc= IPC namespace to use 使用的IPC命名空间 --pid= PID namespace to use 使用的PID命名空间 --uts= UTS namespace to use -l, --label=[] Set meta data on a container 在容器上,设置元数据 --label- file =[] Read in a line delimited file of labels --link=[] Add link to another container 添加一个到另一个容器的连接 --log-driver= Logging driver for container 容器的日志驱动 --log-opt=[] Log driver options --lxc-conf=[] Add custom lxc options 添加定制的lxc选项 -m, --memory= Memory limit 内存限制 --mac-address= Container MAC address (e.g. 92:d0:c6:0a:29:33) 容器的MAC地址 --memory-swap= Total memory (memory + swap), '-1' to disable swap 容器的总内存(物理内容+交换区) --name= Assign a name to the container 为容器分配一个名字 --net=bridge Set the Network mode for the container 为容器设置网络模式 --oom- kill -disable= false Disable OOM Killer -P, --publish-all= false Publish all exposed ports to random ports 把通气端口发布的主机。即容器端口映射到宿主机的任意端口上。 -p, --publish=[] Publish a container's port(s) to the host 把容器的端口发布到主机,即容器端口映射到宿主机的具体端口上。可加上多个-p --privileged= false Give extended privileges to this container 赋予容器扩展权限 -- read -only= false Mount the container's root filesystem as read only 以只读的方式装载容器的根文件系统 --restart=no Restart policy to apply when a container exits -- rm = false Automatically remove the container when it exits 当容器存在时,自动移除容器 --security-opt=[] Security Options 安全选项 --sig-proxy= true Proxy received signals to the process -t, -- tty = false Allocate a pseudo-TTY 分配一个伪终端 -u, --u-user= Username or UID ( format : <name|uid>[:<group|gid>]) -- ulimit =[] Ulimit options - v , --volume=[] Bind mount a volume --volumes-from=[] Mount volumes from the specified container(s) -w, --workdir= Working directory inside the container -------------------------------------------- 当运行docker run命令时,Docker会启动一个进程,并为这个进程分配其独占的文件系统、网络资源和以此进程为根进程的进程组。 在容器启动时,镜像可能已经定义了要运行的二进制文件、暴露的网络端口等,但是用户可以通过docker run命令重新定义(docker run可以控制一个容器运行时的行为,它可以覆盖docker build在构建镜像时的一些默认配置),这也是为什么run命令相比于其它命令有如此多的参数的原因。 使用方法: docker run [OPTIONS] IMAGE [COMMAND] [ARG...] OPTIONS总起来说可以分为两类: a)设置运行方式: 决定容器的运行方式,前台执行还是后台执行; 设置containerID; 设置网络参数; 设置容器的CPU和内存参数; 设置权限和LXC参数; b)设置镜像的默认资源,也就是说用户可以使用该命令来覆盖在镜像构建时的一些默认配置。 docker run [OPTIONS]可以让用户完全控制容器的生命周期,并允许用户覆盖执行docker build时所设定的参数,甚至也可以修改本身由Docker所控制的内核级参数。 Operator exclusive options 当执行docker run时可以设置以下参数: 1.Detached vs Foreground Detached (-d) - Foreground 2.Container Identification Name (--name) - PID Equivalent 3.IPC Setting 4.Network Settings 5.Clean Up (-- rm ) 6.Runtime Constraints on CPU and Memory 7.Runtime Privilege, Linux Capabilities, and LXC Configuration ---------------------------------------------------------------------------------------------- 1.Detached vs foreground 当我们启动一个容器时,首先需要确定这个容器是运行在前台还是运行在后台。 -d= false , 没有附加标准输入、输出、错误 ---- 运行在后台 Detached (-d) docker run -d -d= false --detach= false 那么容器将会运行在后台模式。 此时所有I /O 数据只能通过网络资源或者共享卷组来进行交互,因为容器不再监听你执行docker run的这个终端命令行窗口。 但你可以通过执行docker attach来重新附着到该容器的回话中。 需要注意的是,容器运行在后台模式下,是不能使用-- rm 选项的。 2.Foregroud 不指定-d参数(为明确给-d选项指定值,取默认值 false ) --在前台模式下 Docker会在容器中启动进程,同时将当前的命令行窗口附着到容器的标准输入、标准输出和标准错误中 --- 把当前的命令行窗口附着到容器的标准输入、输出、错误上. 也就是说容器中所有的输出都可以在当前窗口中看到。甚至它都可以虚拟出一个TTY窗口,来执行信号中断。 这一切都是可以配置的: -a=[], --attach=[] 把容器的标准输入、输出、错误附着到当前的命令行窗口 -t= false , -- tty = false 分配一个伪终端 -i= false , --interactive= false 附着标准输入到当前命令行 -------特别注意--------- 注意: -i 选项取默认值( false ) docker run 没有-i选项,相当于docker run -i= false ,即非交互式运行 docker run -i 指定-i选项,即以交互式运行 如果在执行run命令时没有指定-a参数,那么Docker默认会挂载所有标准数据流,包括输入输出和错误,你可以单独指定挂载哪个标准流。 # docker run -a=[stdin, stdout] -i -t ubuntu /bin/bash 如果要进行交互式操作(例如Shell脚本),那我们必须使用-i -t参数同容器进行数据交互。 但是当通过管道同容器进行交互时,就不需要使用-t参数,例如下面的命令: # echo test | docker run -i busybox cat Docker容器识别 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 1.Name(--name) 可以通过三种方式为容器命名: 1)使用UUID长命名( "f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778" ) 2)使用UUID短命令( "f78375b1c487" ) 3)使用Name( "evil_ptolemy" ) 这个UUID标示是由Docker deamon生成的。 如果你在执行docker run时没有指定--name,那么deamon会自动生成一个随机字符串UUID。 但是对于一个容器来说有个name会非常方便,当你需要连接其它容器时或者类似需要区分其它容器时,使用容器名称可以简化操作。无论容器运行在前台或者后台,这个名字都是有效的。 PID equivalent 如果在使用Docker时有自动化的需求,你可以将containerID输出到指定的文件中(PIDfile),类似于某些应用程序将自身ID输出到文件中,方便后续脚本操作。 --cidfile= "" : Write the container ID to the file 2.Image[:tag] 当一个镜像的名称不足以分辨这个镜像所代表的含义时,你可以通过tag将版本信息添加到run命令中,以执行特定版本的镜像。例如:docker run ubuntu:14.04 [root@localhost ~] # docker images REPOSITORY TAG IMAGE ID CREATED SIZE docker.io /uifd/ui-for-docker latest 312812aadc64 34 hours ago 8.096 MB docker.io /nginx latest 5e69fe4b3c31 5 days ago 182.5 MB 192.168.1.23:5000 /tomcat7 latest 47c5123914a1 6 days ago 562.3 MB docker.io /ubuntu latest 0ef2e08ed3fa 4 weeks ago 130 MB docker.io /centos latest 67591570dd29 3 months ago 191.8 MB docker.io /tomcat latest ebb17717bed4 5 months ago 355.4 MB 3.IPC Settings 默认情况下,所有容器都开启了IPC命名空间。 --ipc= "" : Set the IPC mode for the container, 'container:<name|id>' : reuses another container's IPC namespace 'host' : use the host's IPC namespace inside the container IPC(POSIX /SysV IPC)命名空间提供了相互隔离的命名共享内存、信号灯变量和消息队列。 共享内存可以提高进程数据的交互速度。 共享内存一般用在数据库和高性能应用(C /OpenMPI 、C++ /using boost libraries)上或者金融服务上。 如果需要容器中部署上述类型的应用,那么就应该在多个容器直接使用共享内存了。 ---------------------------------------------------------------------------------------------- Network settings 默认情况下,所有的容器都开启了网络接口,同时可以接受任何外部的数据请求。 --dns=[] : Set custom dns servers for the container --net= "bridge" : Set the Network mode for the container ##在docker桥接上,为容器创建一个新的网络栈 'bridge' : creates a new network stack for the container on the docker bridge 'none' : no networking for this container 没有为该容器配置网络 'container:<name|id>' : reuses another container network stack 重用另一个容器的网络栈 'host' : use the host network stack inside the container 在容器内使用主机的网络栈 --add-host= "" : Add a line to /etc/hosts (host:IP) 向容器 /etc/hosts 的文件中增加一行 --mac-address= "" : Sets the container 's Ethernet device' s MAC address 设置容器网卡的MAC地址 你可以通过docker run --net=none来关闭网络接口,此时将关闭所有网络数据的输入输出,你只能通过STDIN、STDOUT或者files来完成I /O 操作。 默认情况下,容器使用主机的DNS设置,你也可以通过--dns来覆盖容器内的DNS设置。 同时Docker为容器默认生成一个MAC地址,你可以通过--mac-address 12:34:56:78:9a: bc 来设置你自己的MAC地址。 Docker支持的网络模式有: none 关闭容器内的网络连接 bridge 通过veth接口来连接容器,默认配置。 host 允许容器使用host的网络堆栈信息。注意:这种方式将允许容器访问host中类似D-BUS之类的系统服务,所以认为是不安全的。 container 使用另外一个容器的网络堆栈信息。 ----None模式---- 将网络模式设置为none时,这个容器将不允许访问任何外部router。 这个容器内部只会有一个loopback接口,而且不存在任何可以访问外部网络的router。 -----Bridge模式----- Docker默认会将容器设置为bridge模式。 此时在主机上面将会存在一个docker0的网络接口,同时会针对容器创建一对veth接口。 其中一个veth接口是在主机充当网卡桥接作用,另外一个veth接口存在于容器的命名空间中,并且指向容器的loopback。 Docker会自动给这个容器分配一个IP,并且将容器内的数据通过桥接转发到外部。 -----Host模式----- 当网络模式设置为host时,这个容器将完全共享host的网络堆栈。 host所有的网络接口将完全对容器开放。 容器的主机名也会存在于主机的 hostname 中。 这时,容器所有对外暴露的端口和对其它容器的连接,将完全失效。 -----Container模式----- 当网络模式设置为Container时,这个容器将完全复用另外一个容器的网络堆栈。同时使用时这个容器的名称必须要符合下面的格式:--net container:<name| id >. 比如当前有一个绑定了本地地址localhost的Redis容器。 如果另外一个容器需要复用这个网络堆栈, 则需要如下操作: # docker run -d --name redis example/redis --bind 127.0.0.1 //use the redis container's network stack to access localhost # docker run --rm -ti --net container:redis example/redis-cli -h 127.0.0.1 管理 /etc/hosts /etc/hosts 文件中会包含容器的 hostname 信息,我们也可以使用--add-host这个参数来动态添加 /etc/hosts 中的数据。 # docker run -ti --add-host db-static:86.75.30.9 ubuntu cat /etc/hosts 172.17.0.22 09d03f76bf2c fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback 86.75.30.9 db-static ##容器启动时添加进来的 地址到主机名映射 ---------------------------------------------------------------------------------------------- Clean up 默认情况下,每个容器在退出时,它的文件系统也会保存下来,这样一方面调试会方便些,因为你可以通过查看日志等方式来确定最终状态。 另外一方面,你也可以保存容器所产生的数据。 但是当你仅仅需要短暂的运行一个容器,并且这些数据不需要保存,你可能就希望Docker能在容器结束时自动清理其所产生的数据。 这个时候你就需要-- rm 这个参数了。 <<<<<< 注意:-- rm 和 -d不能共用 >>>>>> -- rm = false : Automatically remove the container when it exits (incompatible with -d) Security configuration --security-opt= "label:user:USER" : Set the label user for the container --security-opt= "label:role:ROLE" : Set the label role for the container --security-opt= "label:type:TYPE" : Set the label type for the container --security-opt= "label:level:LEVEL" : Set the label level for the container --security-opt= "label:disable" : Turn off label confinement for the container 关闭容器的标签限制 --secutity-opt= "apparmor:PROFILE" : Set the apparmor profile to be applied to the container 你可以通过--security-opt修改容器默认的schema标签。 比如说,对于一个MLS系统来说(译者注:MLS应该是指Multiple Listing System),你可以指定MCS /MLS 级别。 使用下面的命令可以在不同的容器间分享内容: # docker run --security-opt=label:level:s0:c100,c200 -i -t fedora bash 如果是MLS系统,则使用下面的命令: # docker run --security-opt=label:level:TopSecret -i -t rhel7 bash 使用下面的命令可以在容器内禁用安全策略: # docker run --security-opt=label:disable -i -t fedora bash 如果你需要在容器内执行更为严格的安全策略,那么你可以为这个容器指定一个策略替代,比如你可以使用下面的命令来指定容器只监听Apache端口: # docker run --security-opt=label:type:svirt_apache_t -i -t centos bash 注意:此时,你的主机环境中必须存在一个名为svirt_apache_t的安全策略。 Runtime constraints on CPU and memory 下面的参数可以用来调整容器内的性能。 -m= "" : Memory limit ( format : <number><optional unit>, where unit = b, k, m or g) -c=0 : CPU shares (relative weight) 通过docker run -m可以调整容器所使用的内存资源。 如果主机支持swap内存,那么使用-m可以设定比主机物理内存还大的值。 同样,通过-c可以调整容器的CPU优先级。 默认情况下,所有的容器拥有相同的CPU优先级和CPU调度周期,但你可以通过Docker来通知内核给予某个或某几个容器更多的CPU计算周期。 比如,我们使用-c或者--cpu-shares =0启动了C0、C1、C2三个容器,使用-c=512启动了C3容器。 这时,C0、C1、C2可以100%的使用CPU资源(1024),但C3只能使用50%的CPU资源(512) 如果这个主机的操作系统是时序调度类型的,每个CPU时间片是100微秒,那么C0、C1、 C2将完全使用掉这100微秒,而C3只能使用50微秒。 Runtime privilege, Linux capabilities, and LXC configuration --cap-add : Add Linux capabilities --cap-drop : Drop Linux capabilities --privileged= false : Give extended privileges to this container --device=[] : Allows you to run devices inside the container without the --privileged flag. --lxc-conf=[] : (lxc exec -driver only) Add custom lxc options --lxc-conf= "lxc.cgroup.cpuset.cpus = 0,1" 默认情况下,Docker的容器是没有特权的,例如不能在容器中再启动一个容器。这是因为默认情况下容器是不能访问任何其它设备的。但是通过 "privileged" ,容器就拥有了访问任何其它设备的权限。 当操作者执行docker run --privileged时,Docker将拥有访问主机所有设备的权限,同时Docker也会在apparmor或者selinux做一些设置,使容器可以容易的访问那些运行在容器外部的设备。你可以访问Docker博客来获取更多关于--privileged的用法。 同时,你也可以限制容器只能访问一些指定的设备。下面的命令将允许容器只访问一些特定设备: sudo docker run --device= /dev/snd : /dev/snd ... 默认情况下,容器拥有对设备的读、写、创建设备文件的权限。使用:rwm来配合--device,你可以控制这些权限。 # docker run --device=/dev/sda:/dev/xvdc --rm -it ubuntu fdisk /dev/xvdc Command (m for help): q # docker run --device=/dev/sda:/dev/xvdc:r --rm -it ubuntu fdisk /dev/xvdc You will not be able to write the partition table. Command (m for help): q # docker run --device=/dev/sda:/dev/xvdc:w --rm -it ubuntu fdisk /dev/xvdc crash.... # docker run --device=/dev/sda:/dev/xvdc:m --rm -it ubuntu fdisk /dev/xvdc fdisk : unable to open /dev/xvdc : Operation not permitted 使用--cap-add和--cap-drop,配合--privileged,你可以更细致的控制人哦怒气。 默认使用这两个参数的情况下,容器拥有一系列的内核修改权限,这两个参数都支持all值,如果你想让某个容器拥有除了MKNOD之外的所有内核权限,那么可以执行下面的命令: # docker run --cap-add=ALL --cap-drop=MKNOD ... 如果需要修改网络接口数据,那么就建议使用--cap-add=NET_ADMIN,而不是使用--privileged。 # run -t -i --rm ubuntu:14.04 ip link add dummy0 type dummy RTNETLINK answers: Operation not permitted # run -t -i --rm --cap-add=NET_ADMIN ubuntu:14.04 ip link add dummy0 type dummy 如果要挂载一个FUSE文件系统,那么就需要--cap-add和--device了。 如果Docker守护进程在启动时选择了lxclxc-driver(docker -d -- exec -driver=lxc),那么就可以使用--lxc-conf来设定LXC参数。 但需要注意的是,未来主机上的Docker deamon有可能不会使用LXC,所以这些参数有可能会包含一些没有实现的配置功能。 这意味着,用户在操作这些参数时必须要十分熟悉LXC。 特别注意:当你使用--lxc-conf修改容器参数后,Docker deamon将不再管理这些参数,那么用户必须自行进行管理。 比如说,你使用--lxc-conf修改了容器的IP地址,那么在 /etc/hosts 里面是不会自动体现的,需要你自行维护。 把当前用户加入到docker用户组中 usermod -a -G docker $USER =============================== # docker commit -h Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] Create a new image from a container's changes ##从一个容器的改变创建一个新的镜像 -a, --author= Author (e.g., "John Hannibal Smith <hannibal@a-team.com>" ) -c, --change=[] Apply Dockerfile instruction to the created image --help= false Print usage -m, --message= Commit message -p, --pause= true Pause container during commit ============================ # docker tag -h Usage: docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG] Tag an image into a repository ##给镜像打标签入库 -f, --force= false Force --help= false Print usage 给容器打标签 docker tag 11662b14f5e0 ubuntu:jdk1.7 以用户grid_hd登录容器 # docker run -it -u grid_hd ubuntu:hd-salve1 给目录下的所有子目录增加执行权限的脚本 #!/bin/bash find /mnt/sda4/docker/aufs - type d | while read dir do chmod +rx "$dir" done 启动一个docker容器在后台运行 docker run -d IMAGE[:TAG] 命令 docker logs container_id ##打印该容器的输出 [root@localhost ~] # docker run -d --name mytest docker.io/centos /bin/sh -c "while true; do echo hello world; sleep 2; done" 37738fe3d6f9ef26152cb25018df9528a89e7a07355493020e72f147a291cd17 [root@localhost ~] # docker logs mytest hello world hello world hello world hello world docker attach container_id ##附加该容器的标准输出到当前命令行 [root@localhost ~] # docker attach mytest hello world hello world hello world ....... 此时,Ctrl+C退出container(容器消失),按ctrl-p ctrl-q可以退出到宿主机,而保持container仍然在运行 --------------------------------------------------------------- 另外,观察以下几点: commit container只会pause住容器,这是为了保证容器文件系统的一致性,但不会stop。如果你要对这个容器继续做其他修改: 你可以重新提交得到新image2,删除次新的image1 也可以关闭容器用新image1启动,继续修改,提交image2后删除image1 当然这样会很痛苦,所以一般是采用Dockerfile来build得到最终image,参考[] 虽然产生了一个新的image,并且你可以看到大小有100MB,但从commit过程很快就可以知道实际上它并没有独立占用100MB的硬盘空间,而只是在旧镜像的基础上修改,它们共享大部分公共的 "片" 。 有四种不同的选项会影响容器守护进程的服务名称: 1)-h HOSTNAME 或者 -- hostname =HOSTNAME --设置容器的主机名,仅本机可见。 这种方式是写到 /etc/hostname ,以及 /etc/hosts 文件中,作为容器主机IP的别名,并且将显示在容器的 bash 中。 不过这种方式设置的主机名将不容易被容器之外可见。这将不会出现在 docker ps 或者 其他的容器的 /etc/hosts 文件中。 2)--link=CONTAINER_NAME:ALIAS --使用这个选项去run一个容器, 将在此容器的 /etc/hosts 文件中增加一个主机名ALIAS,这个主机名是名为CONTAINER_NAME 的容器的IP地址的别名。 这使得新容器的内部进程可以访问主机名为ALIAS的容器而不用知道它的IP。 --link= 关于这个选项的详细讨论请看: Communication between containers. 3)--dns=IP_ADDRESS --设置DNS服务器的IP地址,写入到容器的 /etc/resolv .conf文件中。当容器中的进程尝试访问不在 /etc/hosts 文件中的主机A 时,容器将以53端口连接到IP_ADDRESS这个DNS服务器去搜寻主机A的IP地址。 4)--dns-search=DOMAIN --设置DNS服务器的搜索域,以防容器尝试访问不完整的主机名时从中检索相应的IP。这是写入到容器的 /etc/resolv .conf文件中的。当容器尝试访问主机 host,而DNS搜索域被设置为 example.com ,那么DNS将不仅去查寻host主机的IP,还去查询host.example.com的 IP。 在docker中,如果启动容器时缺少以上最后两种选项设置时,将使得容器的 /etc/resolv .conf文件看起来和宿主主机的 /etc/resolv .conf文件一致。这些选项将修改默认的设置。 注意一点:当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括: 1 2 3 4 5 6 7 1)检查本地是否存在指定的镜像,不存在就从公有仓库下载 2)利用镜像创建并启动一个容器 3)分配一个文件系统,并在只读的镜像层外面挂载一层可读写层 4)从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去 5)从地址池配置一个 ip 地址给容器 6)执行用户指定的应用程序 7)执行完毕后容器被终止 简单补充下....... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 在ubuntu中安装docker # sudo apt-get install docker.io 查看docker的版本信息 # docker version 查看安装docker的信息 # docker info 查看本机Docker中存在哪些镜像 # docker images ------------------------------------------------------- docker pull 拉取镜像 docker push 推送指定镜像 示例: 下载官方 ubuntu docker 镜像,默认下载所有 ubuntu 官方库镜像 [root@localhost ~] # docker pull ubuntu 下载指定版本 ubuntu 官方镜像 [root@localhost ~] # docker pull ubuntu:14.04 推送镜像库到私有源(可注册 docker 官方账户,推送到官方自有账户) [root@localhost ~] # docker push 192.168.0.100:5000/ubuntu 推送指定镜像到私有源 [root@localhost ~] # docker push 192.168.0.100:5000/ubuntu:14.04 ------------------------------------------------------ 从 Docker Hub 搜索镜像 # docker search ubuntu:14.04 示例: 查找star数至少为10的ubuntu镜像(默认是不加-s选项) [root@localhost ~] # docker search -s 10 ubuntu INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED docker.io docker.io /ubuntu Ubuntu is a Debian-based Linux operating s... 5682 [OK] docker.io docker.io /rastasheep/ubuntu-sshd Dockerized SSH service, built on top of of... 75 [OK] docker.io docker.io /ubuntu-upstart Upstart is an event-based replacement for ... 70 [OK] docker.io docker.io /consol/ubuntu-xfce-vnc Ubuntu container with "headless" VNC sessi... 45 [OK] docker.io docker.io /ubuntu-debootstrap debootstrap --variant=minbase --components... 28 [OK] docker.io docker.io /torusware/speedus-ubuntu Always updated official Ubuntu docker imag... 27 [OK] docker.io docker.io /nickistre/ubuntu-lamp LAMP server on Ubuntu 16 [OK] docker.io docker.io /nuagebec/ubuntu Simple always updated Ubuntu docker images... 16 [OK] ------------------------------------------------------- 显示一个镜像的历史 # docker history birdben/ubuntu:v1 列出一个容器里面被改变的文件或者目 # docker diff birdben/ubuntu:v1 从一个容器中取日志 # docker logs birdben/ubuntu:v1 显示一个运行的容器里面的进程信息 # docker top birdben/ubuntu:v1 从容器里面拷贝文件/目录到本地一个路径 # docker cp ID:/container_path to_path -------------------------------------------------------------------------------------------- 查看容器的root用户密码 # docker logs <容器名orID> 2>&1 | grep '^User: ' | tail -n1 因为Docker容器启动时的root用户的密码是随机分配的。所以,通过这种方式就可以得到redmine容器的root用户的密码了。 查看容器日志 # docker logs -f <容器名orID> ----------------------------------------------------------------------------------- 运行一个新容器,同时为它命名、端口映射、文件夹映射。以redmine镜像为例 # docker run --name redmine -p 9003:80 -p 9023:22 -d -v /var/redmine/files:/redmine/files -v /var/redmine/mysql:/var/lib/mysql sameersbn/redmine 一个容器连接到另一个容器 # docker run -i -t --name sonar -d -link mmysql:db tpires/sonar-server sonar 容器连接到mmysql容器,并将mmysql容器重命名为db。这样,sonar容器就可以使用db的相关的环境变量了。 检查某一特定容器可以使用docker inspect命令,后面跟容器的名称或唯一ID。 Docker自动创建的容器名称同样是不方便记忆的,所以最好在运行容器时使用--name参数为其指定一个名称,命令格式为docker run --name=<yourname>。 # docker inspect App_Container 使用logs命令查看守护式容器 可以通过使用docker logs命令来查看容器的运行日志,其中-- tail 选项可以指定查看最后几条日志,而-t选项则可以对日志条目附加时间戳。使用-f选项可以跟踪日志的输出,直到手动停止。 docker logs [OPTIONS] CONTAINER # docker logs App_Container 查看运行中容器内的进程 docker top CONTAINER [ ps OPTIONS] # docker top App_Container 构建自己的镜像 # docker build -t <镜像名> <Dockerfile路径> 如Dockerfile在当前路径: # docker build -t xx/gitlab . 重新查看container的stdout # 启动top命令,后台运行 $ ID=$( sudo docker run -d ubuntu /usr/bin/top -b) # 获取正在running的container的输出 $ sudo docker attach $ID top - 02:05:52 up 3:05, 0 users , load average: 0.01, 0.02, 0.05 Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie Cpu(s): 0.1%us, 0.2%sy, 0.0%ni, 99.7% id , 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 373572k total, 355560k used, 18012k free , 27872k buffers Swap: 786428k total, 0k used, 786428k free , 221740k cached ^C$ $ sudo docker stop $ID 后台运行(-d)、并暴露端口(-p) # docker run -d -p 127.0.0.1:33301:22 centos6-ssh 从Container中拷贝文件出来 # sudo docker cp 7bb0e258aefe:/etc/debian_version . 拷贝7bb0e258aefe中的 /etc/debian_version 到当前目录下。 注意:只要7bb0e258aefe没有被删除,文件命名空间就还在,可以放心的把 exit 状态的container的文件拷贝出来 列出当前所有正在运行的容器 1 2 3 4 5 # docker ps # docker ps -a 为查看所有的容器,包括已经停止的。 # docker ps -q 查找已运行的docker容器的ID # docker ps -a -q 查找所有的docker容器的ID # docker ps -l 列出最近一次启动的容器 查看容器的相关信息 # docker inspect CONTAINER_ID 显示容器IP地址和端口号,如果输出是空的说明没有配置IP地址(不同的Docker容器可以通过此IP地址互相访问) # docker inspect --format='{{.NetworkSettings.IPAddress}}' CONTAINER_ID 保存对容器的修改 # docker commit -m "Added ssh from ubuntu14.04" -a "birdben" 6s56d43f627f3 birdben/ubuntu:v1参数: -m参数用来来指定提交的说明信息; -a可以指定用户信息的; 6s56d43f627f3代表的时容器的id; birdben/ubuntu:v1指定目标镜像的用户名、仓库名和 tag 信息。 构建一个容器 # docker build -t="birdben/ubuntu:v1" .参数: -t为构建的镜像制定一个标签,便于记忆/索引等 . 指定Dockerfile文件在当前目录下,也可以替换为一个具体的 Dockerfile 的路径。 在docker中运行ubuntu镜像 # docker run <相关参数> <镜像 ID> <初始命令> 守护模式启动 # docker run -it ubuntu:14.04 交互模式启动 # docker run -it ubuntu:14.04 /bin/bash 指定端口号启动 # docker run -p 80:80 birdben/ubuntu:v1 指定配置启动 # sudo docker run -d -p 10.211.55.4:9999:22 birdben/ubuntu:v1 '/usr/sbin/sshd' -D 参数: -d:表示以“守护模式”执行,日志不会出现在输出终端上。 -i:表示以“交互模式”运行容器,-i 则让容器的标准输入保持打开 -t:表示容器启动后会进入其命令行,-t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上 -v:表示需要将本地哪个目录挂载到容器中,格式:-v <宿主机目录>:<容器目录>,-v 标记来创建一个数据卷并挂载到容器里。在一次 run 中多次使用可以挂载多个数据卷。 -p:表示宿主机与容器的端口映射,此时将容器内部的 22 端口映射为宿主机的 9999 端口,这样就向外界暴露了 9999 端口,可通过 Docker 网桥来访问容器内部的 22 端口了。注意: 这里使用的是宿主机的 IP 地址:10.211.55.4,与对外暴露的端口号 9999,它映射容器内部的端口号 22。ssh外部需要访问:ssh root@10.211.55.4 -p 9999 不一定要使用“镜像 ID”,也可以使用“仓库名:标签名” 根据镜像启动容器的时候,如果镜像的TAG是latest,那么就直接跟镜像名就行了;如果TAG不是latest,那么镜像后面要跟上这个TAG标识。如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 [root@linux-node2 ~] # docker images REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu latest 0ef2e08ed3fa 2 weeks ago 130 MB centos7 7.3.1611 d5ebea14da54 3 weeks ago 311 MB 由于ubuntu镜像的TAG标识是latest,那么容器启动的时候,镜像后面的TAG信息可以省略。 [root@linux-node2 ~] # docker run -i -t ubuntu /bin/bash 但是centos7镜像的TAG标识不是latest,所以容器启动的时候必须要跟上这个TAG信息。 [root@linux-node2 ~] # docker run -i -t centos7:7.3.1611 /bin/bash [root@2ba57568e836 /] # cat /etc/redhat-release CentOS Linux release 7.3.1611 (Core) 不跟TAG的话,就会报错 [root@linux-node2 ~] # docker run -i -t centos7 /bin/bash Unable to find image 'centos7:latest' locally Pulling repository docker.io /library/centos7 docker: Error: image library /centos7 :latest not found. See 'docker run --help' . docker运行一个容器必须是基于镜像来进行的,一旦容器启动了,我们就可以登录到容器中,安装自己所需的软件或应用程序。启动容器的命令中必须跟一个镜像,启动容器后执行的命令必须放在镜像后面,如下,/bin/bash必须放在镜像名称的后面: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 [root@linux-node2 ~] # docker run -i -t daocloud.io/library/ubuntu /bin/bash root@a7b997da8ba3:/ # cat /etc/issue Ubuntu 16.04.1 LTS \n \l root@a7b997da8ba3:/ # [root@linux-node2 ~]# docker run -i -t ubuntu /bin/bash root@d96c6b85cace:/ # cat /etc/issue Ubuntu 16.04.1 LTS \n \l root@d96c6b85cace:/ # [root@linux-node2 ~] # docker run -t -i -v /home/wangshibo/docker:/home/mycontainer:rw -p 8888:8080 centos /bin/bash [root@8f65f826ad80 /] # [root@linux-node2 ~] # docker run -i -t centos7:7.3.1611 /bin/bash [root@4941394a1e92 /] # cat /etc/redhat-release CentOS Linux release 7.3.1611 (Core) [root@linux-node2 ~] # docker run -i -t centos:centos6 /bin/bash [root@357eaa658c87 /] # cat /etc/redhat-release CentOS release 6.8 (Final) 注意:创建应用容器的时候,一般会做端口映射,这样是为了让外部能够访问这些容器里的应用。可以通过-P或-p参数来指定端口映射 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 1)当使用-p标记时,可以指定端口映射,即容器端口映射到宿主机的对应端口。可以用多个-p指定多个端口映射关系。如下: [root@localhost ~] # docker images REPOSITORY TAG IMAGE ID CREATED SIZE docker.io /redis latest e4a35914679d 2 weeks ago 182.9 MB [root@localhost ~] # docker run --name myredis -p 63799:6379 -d docker.io/redis f5d5ff51ace01c5f26fcd65a6ca4853f8556a333c812576123ed71fd3d405737 [root@localhost ~] # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f5d5ff51ace0 docker.io /redis "docker-entrypoint.sh" 6 seconds ago Up 5 seconds 0.0.0.0:63799->6379 /tcp myredis [root@localhost ~] # docker run --rm -it --name myredis2 --link myredis:redisdb docker.io/redis /bin/bash root@16b660ff9f65: /data # redis-cli -h redisdb -p 6379 redisdb:6379> ping PONG redisdb:6379> set test linux OK redisdb:6379> 在别的机器上通过访问本机的63799端口连接这个容器的redis [root@linux-node2 ~] # redis-cli -h 192.168.1.23 -p 63799 192.168.1.23:63799> get test "linux" 192.168.1.23:63799> ------------------------------------------------------------------------------------------ 可以使用多个-p映射多个端口 [root@localhost ~] # docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos7 7.3.1611 d5ebea14da54 3 weeks ago 311 MB [root@localhost ~] # docker run -i -t -p 20022:22 -p 8088:80 centos7:7.3.1611 /bin/bash [root@1a7a949e2f41 /] # ------------------------------------------------------------------------------------------ 2)当使用-P标记时,Docker 会随机映射一个 49000~49900 的端口到内部容器开放的网络端口。如下: [root@localhost ~] # docker images REPOSITORY TAG IMAGE ID CREATED SIZE docker.io /redis latest e4a35914679d 2 weeks ago 182.9 MB [root@localhost ~] # docker run --name myredis -P -d docker.io/redis 805d0e21e531885aad61d3e82395210b50621f1991ec4b7f9a0e25c815cc0272 [root@localhost ~] # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 805d0e21e531 docker.io /redis "docker-entrypoint.sh" 4 seconds ago Up 3 seconds 0.0.0.0:32768->6379 /tcp myredis 从上面的结果中可以看出,本地主机的32768端口被映射到了redis容器的6379端口上,也就是说访问本机的32768端口即可访问容器内redis端口。 测试看下,登陆redis容器,随意写个数据 [root@localhost ~] # docker run --rm -it --name myredis2 --link myredis:redisdb docker.io/redis /bin/bash root@be44d955d6f4: /data # redis-cli -h redisdb -p 6379 redisdb:6379> set wangshibo huanqiu OK redisdb:6379> 在别的机器上通过上面映射的端口32768连接这个容器的redis [root@linux-node2 ~] # redis-cli -h 192.168.1.23 -p 32768 192.168.1.23:32768> get wangshibo "huanqiu" start 启动容器(多个容器,后面就跟多个容器id) # docker start 117843ade696117843ade696 stop 停止正在运行的容器(多个容器,后面就跟多个容器id)(在容器里面按ctrl+d组合键,也会退出当前容器) # docker stop 117843ade696117843ade696 restart 重启容器(多个容器,后面就跟多个容器id) # docker restart 117843ade696117843ade696 删除容器和镜像 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 rm 删除容器(删除一个或多个,多个之间用空格隔开) # docker rm 117843ade696117843ade696 杀死所有running状态的容器 # docker kill $(docker ps -a -q) # docker rm $(docker ps -a -q) ----------------------------------------------------------------------------------- rmi 删除镜像(删除一个或多个,多个之间用空格隔开) # docker rmi ed9c93747fe1Deleted 删除所有未打tag的镜像 # docker rmi $(docker images -q | awk '/^<none>/ { print $3 }') 删除所有镜像 # docker rmi $(docker images -q) 根据格式删除所有镜像 # docker rm $(docker ps -qf status=exited) 登录Docker Hub中心 # docker login 发布上传image(push) # docker push birdben/ubuntu:v1 Docker本机和容器之间的文件拷贝: 1 2 3 4 5 1)将本机的 /root/test . file 文件传输到ID为7bb0e258aefe的容器里的 /mnt/wang 目录下 # docker cp /root/test.file 7bb0e258aefe:/mnt/wang/ 2)拷贝ID为7bb0e258aefe的容器里的 /var/id .list文件到本机的 /opt 下 # docker cp 7bb0e258aefe:/var/id.list /opt/ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 实例如下: [root@linux-node2 ~] # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c7bd050b0a23 centos "/bin/bash" 2 hours ago Up 2 hours small_almeida eaf66f1e43ab centos "/sbin/init" 7 weeks ago Up 7 weeks 0.0.0.0:8888->8080 /tcp hungry_khorana [root@linux-node2 ~] # docker exec -it eaf66f1e43ab /bin/bash [root@eaf66f1e43ab /] # cd /mnt/ [root@eaf66f1e43ab mnt] # ls [root@eaf66f1e43ab mnt] # mkdir test-haha [root@eaf66f1e43ab mnt] # cd test-haha [root@eaf66f1e43ab test -haha] # touch a b c [root@eaf66f1e43ab test -haha] # pwd /mnt/test-haha [root@eaf66f1e43ab test -haha] # ls a b c [root@eaf66f1e43ab test -haha] # 然后拷贝容器文件出来 [root@linux-node2 ~] # docker cp eaf66f1e43ab:/mnt/test-haha /opt/ [root@linux-node2 ~] # ls /opt/test-haha/ a b c 镜像的存出和载入(可以将本机下载的镜像导出,然后将导出文件上传到别的机器上,在别的机器上进行镜像导入) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 1)如果要导出镜像到本地文件,可以使用 docker save命令。 拉取镜像 [root@linux-node2 ~] # docker pull ubuntu:14.04 [root@linux-node2 ~] # docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE ubuntu 14.04 c4ff7513909d 5 weeks ago 225.4 MB 导出镜像 [root@linux-node2 ~] # docker save ubuntu:14.04 > /opt/ubuntu_14.04.tar.gz 或者: [root@linux-node2 ~] # docker save -o /opt/ubuntu_14.04.tar.gz ubuntu:14.04 2)将上面的镜像导出文件上传到linux-node1机器上,然后在linux-node1机器上使用docker load命令载入这个镜像 [root@linux-node1 ~] # docker load < /opt/ubuntu_14.04.tar.gz 或者: [root@linux-node1 ~] # docker load --input ubuntu_14.04.tar 实例如下: [root@linux-node2 opt] # docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos7 7.3.1611 1d7e06aab5db 24 hours ago 264.7 MB nginx 1.9 c8c29d842c09 9 months ago 182.7 MB [root@linux-node2 opt] # docker save nginx:1.9 > /opt/nginx:1.9.tar.gz [root@linux-node2 opt] # ls nginx:1.9. tar .gz [root@linux-node2 opt] # rsync -e "ssh -p22" -avpgolr /opt/nginx:1.9.tar.gz 192.168.1.23:/opt/ 登陆192.168.1.23 [root@localhost ~] # cd /opt/ [root@localhost opt] # ls nginx:1.9. tar .gz [root@localhost opt] # docker images REPOSITORY TAG IMAGE ID CREATED SIZE docker.io /centos latest 980e0e4c79ec 5 months ago 196.7 MB docker.io /redis 2.8.19 dd9fe7db5236 22 months ago 110.7 MB 导入nginx镜像 [root@localhost opt] # docker load < /opt/nginx:1.9.tar.gz [root@localhost opt] # docker images REPOSITORY TAG IMAGE ID CREATED SIZE docker.io /centos latest 980e0e4c79ec 5 months ago 196.7 MB nginx 1.9 c8c29d842c09 9 months ago 182.7 MB docker.io /redis 2.8.19 dd9fe7db5236 22 months ago 110.7 MB 容器的导出和导入(可以依据导出的容器快照导入为镜像,在本地或将容器快照文件上传到别的机器上进行导入镜像操作都可以) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 1)导出容器 如果要导出本地某个容器,可以使用 docker export 命令。 [root@linux-node2 ~] # docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5243af7921c5 centos "/bin/bash" 2 days ago Exited (0) 5 seconds ago sharp_saha [root@linux-node2 ~] # docker export 5243af7921c5 > /opt/centos.tar.gz [root@linux-node2 ~] # ls /opt/ centos. tar .gz 这样将导出上面的ID为5243af7921c5的容器快照到本地的 /opt/centos . tar .gz文件了。 2)导入容器快照 可以使用 docker import 从容器快照文件中再导入为镜像 为了测试效果,先删除ID为5243af7921c5的容器,再导入 [root@linux-node2 ~] # docker rm 5243af7921c5 5243af7921c5 [root@linux-node2 ~] # cat /opt/centos.tar.gz | docker import - test/centos:v1.0 sha256:d84d758c5cda4aced7cd24a4efefedb3d56076ae127133dac8ac79ca0bab3f3d 或者使用下面命令导入 [root@linux-node2 ~] # docker import /opt/centos.tar.gz test/centos:v1.0 [root@linux-node2 ~] # docker images REPOSITORY TAG IMAGE ID CREATED SIZE test /centos v1.0 d84d758c5cda 5 seconds ago 191.8 MB [root@linux-node2 ~] # docker run -t -i test/centos:v1.0 /bin/bash [root@5056db543cc2 /] # [root@linux-node2 ~] # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5056db543cc2 test /centos :v1.0 "/bin/bash" 19 seconds ago Up 18 seconds tiny_dijkstra 这个ID为5056db543cc2的新容器既是导入的上面的容器快照创建的 温馨提示: 用户既可以使用docker load来导入镜像存储文件到本地镜像库,也可以使用docker import 来导入一个容器快照到本地镜像库。 这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。 此外,从容器快照文件导入时可以重新指定标签等元数据信息。 比如说我在A机器上有个nginx容器,现在要在B机器上启动一个一模一样的nginx容器(或者说将A机器上的nginx容器拿到B机器上),方法有下面两种: 1 2 1)将A机器上将nginx容器提交为新的镜像(docker commit),然后将这个镜像导出并上传到B机器上,最后在B机器上导入这个新镜像并依据这个镜像启动容器,这个就和A机器上的nginx容器一样了。 2)将A机器上的nginx容器做快照,然后从这个快照文件中导入为镜像,将这个镜像上传到B机器上,最后在B机器上导入这个新镜像并依据它启动容器。 在运行状态中的容器内再次启动新的进程(docker exec) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 虽然Docker鼓励我们一个容器只运行一个服务,但是当我们需要对运行中的容器进行监控、维护和管理时,通常需要为运行中的容器启动新进程。 # docker exec [OPTIONS] CONTAINER COMMAND [ARG...] 这条命令与docker run极为相似,也可以使用-i、-t和-d等参数。 [root@linux-node2 ~] # docker exec -i -t App_Container /bin/bash 示例如下: 创建一个tomcat容器(创建容器后,启动容器的 /bin/bash 进程) [root@localhost ~] # docker run -t -i -d --name=tomcat --hostname=wangshibo --dns=8.8.8.8 -p 8888:8080 tomcat7 /bin/bash a5ab82945a88d16c51941c7fbc1e3f581823099835f96423c4fd19b44841b31c [root@localhost ~] # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a5ab82945a88 tomcat7 "/bin/bash" 3 seconds ago Up 2 seconds 0.0.0.0:8888->8080 /tcp tomcat 在上面tomcat容器已经启动的状态下,再在宿主机上启动该容器中新的进程。(当然也可以直接登陆容器内启动这个进程) [root@localhost ~] # docker exec tomcat /usr/local/tomcat7/bin/startup.sh //如果启动后出现卡的情况,就ctrl+c,不影响启动结果。 Tomcat started. 登陆到该容器内验证,发现tomcat进程已经通过上面的docker exec 启动了 [root@localhost ~] # docker start tomcat tomcat [root@localhost ~] # docker attach tomcat [root@wangshibo /] # ps -ef|grep tomcat root 40 1 19 09:17 ? 00:00:08 java -Djava.util.logging.config. file = /usr/local/tomcat7/conf/logging .properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed. dirs = /usr/local/tomcat7/endorsed -classpath /usr/local/tomcat7/bin/bootstrap .jar: /usr/local/tomcat7/bin/tomcat-juli .jar -Dcatalina.base= /usr/local/tomcat7 -Dcatalina.home= /usr/local/tomcat7 -Djava.io.tmpdir= /usr/local/tomcat7/temp org.apache.catalina.startup.Bootstrap start root 77 1 0 09:17 ? 00:00:00 grep --color=auto tomcat -----------------------------------------------------------------------------------------------------------一般来说,容器创建后的主机名都是随机生成的一串字符。DNS也是默认和宿主机一样的(/etc/resolv.conf) 容器创建后,登陆容器是无法修改主机名或DNS配置的,会报错说:需要root权限才能修改! 其实容器的主机名或DNS配置是可以在容器创建的时候手动指定的: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49

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

Laravel 学习路线【4】控制器

控制器简介 控制器可以将相关的HTTP 请求封装到一个勒种进行处理,控制器目录在 app/Http/Controllers 目录中 定义控制器 <?php namespace App\Http\Controllers; use App\User; use App\Http\Controlelrs\Controller; class UserController extends Controller { //为指定用户显示详情 public function show($id) { return view('user.profile',['user' => User::findOrFail($id)]); } } 我们可以这样定义路由 Route::get('user/{id}','UserController@show'); 如果一个请求匹配到上面URI UserController 的 show 方法就会被执行。路由参数也会传递给当前方法 单动作控制器 如果你想定义一个只处理一个动作的控制器,可以在控制器中定义 __invoke 方法。 <?php namespace App\Http\Controllers; use App\User; use App\Http\Controllers\Controller; class ShowProfile extends Controller { public function __invoke($id) { return view('user.profile',['users' => findOrFail($id)]); } } 当你为这个单动作控制器注册路由的时候,不需要指定方法: Route::get('user/{id}','ShowProfile'); 控制器中间件 中间件可以像这样分配给控制器路由 Route::get('profile','UserController@show')->middleware('auth'); 但是,将中间件放在控制器构造函数中更方便,在控制器的构造函数中使用 middleware 方法你可以很轻松的分配中间件给该控制器。 class UserController extends Controller { //实例化一个新的UserController 实例 public function __construct() { $this->middleware('auth'); $this->middleware('log')->only('index'); $this->middleware('subscribed')->except('store'); } } 在控制器中还可以使用闭包注册中间件,这为我们定义只在某个控制器中使用中间件提供了方便,无需定义完整的中间件类: $this->middleware(function($request,$next){ return $next($request); }) 注:你还可以将中间件分配给多个控制器动作,不过,这意味着你的控制器会变得越来越臃肿,这种情况下,需要考虑将控制器分割成多个更小的控制器。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

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

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应用均可从中受益。

Rocky Linux

Rocky Linux

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

用户登录
用户注册