5月 21

docker run –name ub -d -it bernhard/gitlab-ci-react-native-android /bin/bash

docker exec -it ub bash

android update sdk –no-ui –all –filter tools,platform-tools,android-28,build-tools-28.0.3

打包

docker commit ub oceanheyang/gitlab-ci-react-native-android

推送

docker push oceanheyang/gitlab-ci-react-native-android

written by ocean

5月 07

docker pull gitlab/gitlab-ce

sudo docker run –detach \
–hostname 172.28.3.165 \
–publish 8443:443 –publish 80:80 –publish 822:22 \
–name gitlab \
–restart always \
–volume /ocean/gitlab/config:/etc/gitlab \
–volume /ocean/gitlab/logs:/var/log/gitlab \
–volume /ocean/gitlab/data:/var/opt/gitlab \
gitlab/gitlab-ce

安装gitlab-runner

sudo docker run -d –name gitlab-runner –restart always -v /ocean/gitlab-runner/config:/etc/gitlab-runner -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:latest

配置gitlab-runner,按照提示填即可

sudo docker exec -it gitlab-runner gitlab-ci-multi-runner register

docker run –name ihostel -d -p 8001:80 -v /ocean/www/ihostel/:/wwwroot -w /wwwroot/ microsoft/dotnet dotnet /wwwroot/Ascend.iHostel.NetCoreMVC.Web.dll

image: oceanheyang/dotnet:2.2

stages:
    - deploy
    
variables:    
    HOST: ${HOST}
    USERNAME: ${USERNAME}
    PROJECT: "ihostel"
    PUBLISHER: "bin//release//netcoreapp2.1//publish//"
    REMOTEDIR: "/ocean/www/$PROJECT/"
    BAKDIR: "/ocean/bak/$CI_JOB_ID"
    PROJECTFOLDER: "Ascend.FrameworkCore.Example.Web"
    

before_script:
  - mkdir ~/.ssh
  - echo "StrictHostKeyChecking no" >> ~/.ssh/config
  - export SSHPASS=${PASSWORD}
  
deploy:
    stage: deploy
    tags: 
        - r
    script:  
    
        - cd $PROJECTFOLDER
        - dotnet publish -c release

        - sshpass -e ssh $USERNAME@$HOST "rm -r -f $REMOTEDIR"
        
        - cd $PUBLISHER
      
        - sshpass -e rsync -avz --exclude='.git' --exclude='.gitlab-ci.yml' . $USERNAME@$HOST:$REMOTEDIR

        - sshpass -e ssh $USERNAME@$HOST 'docker restart ihostel'

接下啦安装jenkins

docker run -p 8080:8080 –name jenkins -p 50000:50000 -d -v /ocean/jenkins:/var/jenkins_home jenkins

运行发现没有权限

chmod -R 777 /ocean/jenkins

wiki系统

docker run -d -p 8000:80 –name wiki \
-v /ocean/dokuwiki/data:/dokuwiki/data \
-v /ocean/dokuwiki/conf:/dokuwiki/conf \
-v /ocean/dokuwiki/lib/plugins:/dokuwiki/lib/plugins \
-v /ocean/dokuwiki/lib/tpl:/dokuwiki/lib/tpl \
-v /ocean/dokuwiki/logs:/var/log \
mprasil/dokuwiki

written by ocean

4月 17

npm config set proxy=http://172.28.40.4:80
npm config set registry=http://registry.npmjs.org

npm config set https-proxy=http://172.28.40.4:80
npm config set registry=https://registry.npmjs.org/

npm 全局安装 appium,使用命令(默认安装最新版本):
npm install appium -g

安装 appium 完成后,继续安装 appium-doctor

npm install appium-doctor -g

使用 appium-doctor 检查所有配置均已正确即表示安装成功

npm config delete proxy
npm config delete https-proxy

written by ocean

6月 05

写了个简单的代码生成工具。不愿意使用拼接字符串的方式,所以将目光投向了Razor

在.Net Framework时代,我们可以直接只用 RazorEngine 做执行输出。

但是我试了发现不支持.Net Core大的版本,所以上github看了看,发现了替代品RazorLight

 

使用起来很简单,在Nuget上有包

Install-Package RazorLight

一般调用方式

            var engine = new RazorLightEngineBuilder()
              .UseFilesystemProject(@"D:\Test\CoreTest\ConsoleApp.RazorConsole")
              .UseMemoryCachingProvider()
              .Build();
            string result = engine.CompileRenderAsync("Ocean.cshtml",
                new { Name = "Ocean" }).Result;

Ocean.cshtml是我的razor文件

@{
}
这是一个测试,我是 @Model.Name

 

另外我做了一个简单封装

        public static string ExeRazor(string template,object obj)
        {
            var path = IOHelper.RootDevPath; 
            var engine = new RazorLightEngineBuilder()
             .UseFilesystemProject(path)
             .UseMemoryCachingProvider()
             .Build(); 
            string result = engine.CompileRenderAsync(template, obj).Result;
            return result;
        }

 

好了,这样就可以使用razor做一些string的输出了,比拼接字符串是方便了不少。

最关键的是,我可以直接打包进dll中,既干净又清爽,实在是居家旅行之良品。

 

项目官网上有更多的使用方法。

项目地址:https://github.com/toddams/RazorLight

written by ocean

5月 28

分布式锁就不多介绍了,刚好有一个这样的需求,就上github上找一找,发现一个分布式锁的项目,使用的是redis

项目地址:https://github.com/samcook/RedLock.net

首先使用nuget安装dll

 RedLock.net

我这边做了一个模拟测试,因为实在太简单了,直接看注释就可以了

        static int MAX_THREAD = 5;//模拟5个线程

        static void Main(string[] args)
        {

            var start = DateTime.Now;

            var endPoints = new List<RedLockEndPoint>
            {
                new DnsEndPoint("172.28.3.125", 6379),
            };
            var redlockFactory = RedLockFactory.Create(endPoints);
             
            List<Task> list = new List<Task>();
            for (int i = 0; i < MAX_THREAD; i++)
            {
                Task t = new Task(() =>
                {
                    for (int index = 0; index < 100; index++)
                    { 
                        var id = index % 10; 
                        var expiry = TimeSpan.FromSeconds(30);
                        var key = "key" + id;
                        var wait = TimeSpan.FromSeconds(30);
                        var retry = TimeSpan.FromSeconds(1);
                        using (var redLock = redlockFactory.CreateLock(key, expiry, wait, retry))
                        {
                            if (redLock.IsAcquired)
                            {
                                var info = LockTestDAL.GetLockTestInfo(id);
                                info.Result1++;
                                LockTestDAL.Update(info);
                                info.Result2++;
                                LockTestDAL.Update(info);
                                info.Result3++;
                                LockTestDAL.Update(info);
                            }
                        } 
                    }
                });
                list.Add(t);
            }
            for (int i = 0; i < list.Count; i++)
            {
                list[i].Start();
            }

            Task.WaitAll(list.ToArray());

            Console.WriteLine("done");
            var d = (DateTime.Now - start).TotalSeconds;
            Console.WriteLine($"耗时{d}秒");
            Console.ReadLine(); 
        }

其中有几个参数

expiry是指的超时时间,如果内部执行超过expity则会释放锁

key就是锁定时候的数据特征,一般是主键

wait是指获取锁的时候等待的时间

retry是指每隔多少时间请求一次。

 

一定要注意,锁不是一定能拿到的,所以需要加判断

if (redLock.IsAcquired) //判断是否拿到锁

 

在我的测试用例中,表中有多个数据需要更新,如果不加锁的话会有脏读脏写,数据明显错误,执行大概34秒。

加锁之后数据完全正确,执行时间会稍长,大概38秒。

written by ocean

4月 15

做多服务器集群的时候,需要处理session。

一般两种处理方法,

第一,无session,就是不用session,不用session的话自然没有问题

第二,集中化session,所有session集中放在redis种。这样也没有问题

 

记录一下集中化session

首先引用包

Microsoft.AspNetCore.Session
Microsoft.Extensions.Caching.Redis.Core

 在startup中添加中间件

            services.AddDistributedRedisCache(option =>
            {
                //redis 数据库连接字符串
                option.Configuration = "192.168.1.132:6379";
                //redis 实例名
                option.InstanceName = "master";
            });
            services.AddSession();
            
            //添加使用
            app.UseSession();

这样就可以了。真是太方便了

 

【Session 写入方法】

HttpContext.Session.SetString("key", "strValue");

【Session 读取方法】

HttpContext.Session.GetString("key")

 另外,页面上为了区分不同的server,这里取一下hostname

var hostname= Environment.GetEnvironmentVariable("COMPUTERNAME") ??Environment.GetEnvironmentVariable("HOSTNAME");

 

 

接下来,在docker中部署了5台app,1台nginx做负载均衡器,1台redis做session缓存。 记录下脚本

docker stop a1
docker stop a2
docker stop a3
docker stop a4
docker stop a5
docker rm a1
docker rm a2
docker rm a3
docker rm a4
docker rm a5
docker run --name a1 --restart=always -d -p 8001:80 -v /ocean/www:/wwwroot -w /wwwroot/ microsoft/aspnetcore dotnet /wwwroot/WebApplication1.dll
docker run --name a2 --restart=always -d -p 8002:80 -v /ocean/www:/wwwroot -w /wwwroot/ microsoft/aspnetcore dotnet /wwwroot/WebApplication1.dll
docker run --name a3 --restart=always -d -p 8003:80 -v /ocean/www:/wwwroot -w /wwwroot/ microsoft/aspnetcore dotnet /wwwroot/WebApplication1.dll
docker run --name a4 --restart=always -d -p 8004:80 -v /ocean/www:/wwwroot -w /wwwroot/ microsoft/aspnetcore dotnet /wwwroot/WebApplication1.dll
docker run --name a5 --restart=always -d -p 8005:80 -v /ocean/www:/wwwroot -w /wwwroot/ microsoft/aspnetcore dotnet /wwwroot/WebApplication1.dll

测试了一下,果然高兴的太早,试了一下,当server变化的时候,session不会同步。这是个问题,继续研究。

 

session其实是根据cookie的一个值来取的,而这个值得不同是因为.net core对其做了数据保护(data Protection) 

数据保护会调用机器自身的一个key值,该key值每台机器都不一样,因此最终造成cookie的值也不一样

 

为了解决这个问题。.Net Core团队提供了包将秘钥保存到redis中

添加包引用

Microsoft.AspNetCore.DataProtection.Redis

修改startup文件如下

            var redis = ConnectionMultiplexer.Connect("192.168.1.132:6379");
            services.AddDataProtection()
                .SetApplicationName("session_application_name")
                .PersistKeysToRedis(redis, "DataProtection-Keys");
            services.AddDistributedRedisCache(option =>
            {
                //redis 数据库连接字符串
                option.Configuration = "192.168.1.132:6379";
                //redis 实例名
                option.InstanceName = "master";
            });
            services.AddSession();

这次是真的OK了。哈哈哈

 

另外之前有写过一篇类似的 

http://blog.wx6.org/2017/929.htm

written by ocean

4月 03

这个功能很有意思。直接引用dll即可以浏览页面。

方法很简单,要被共享的功能单独写成一个.net core的webapplication

 

在另外一个.net core的webapplication中引用上面的dll,切记不要忘掉PrecompiledViews

之后在使用共享UI的dll应用中,startup中添加如下代码即可

 public void ConfigureServices(IServiceCollection services)
        {
            var assembly = typeof(OceanController).GetTypeInfo().Assembly;
            services.AddMvc()
            .AddApplicationPart(assembly);  
            services.Configure<RazorViewEngineOptions>(options =>
            {
                options.FileProviders.Add(
                    new EmbeddedFileProvider(typeof(OceanController).GetTypeInfo().Assembly));
            });
        }

OceanController即共享UI的Controller

written by ocean

1月 03
Vue.js(读音 /vjuː/, 类似于 view)是一个构建数据驱动的 web 界面的库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

Vue.js 自身不是一个全能框架——它只聚焦于视图层。因此它非常容易学习,非常容易与其它库或已有项目整合。另一方面,在与相关工具和支持库一起使用时,Vue.js 也能完美地驱动复杂的单页应用。

页面首先需要引用vue.js

    <script src="https://cdn.bootcss.com/vue/2.5.13/vue.min.js"></script>

一个最简单的例子

    <div id="app">
        <p>{{ message }}</p>
        <input v-model="message">
    </div> 
    <script>
        new Vue({
            el: '#app',
            data: {
                message: 'Hello Vue.js!'
            }
        }) 
    </script>

written by ocean

11月 10
<!doctype html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>
		<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
		<script type="text/javascript">
document.addEventListener('plusready', function(){
var xhr = new plus.net.XMLHttpRequest();
xhr.onreadystatechange = function () {
	switch ( xhr.readyState ) {
		case 0:
			//alert( "xhr请求已初始化" );
		break;
		case 1:
			/alert( "xhr请求已打开" );
		break;
		case 2:
			//alert( "xhr请求已发送" );
		break;
		case 3:
			//alert( "xhr请求已响应");
			break;
		case 4:
			if ( xhr.status == 200 ) {
				alert( "xhr请求成功:"+xhr.responseText );
			} else {
				alert( "xhr请求失败:"+xhr.readyState );
			}
			break;
		default :
			break;
	}
}
xhr.open( "GET", "http://hq.sinajs.cn/list=sz000559,sh603729,sh600460,sz300056,sz002558,sz000037,sz002236,sz000546,sh603959,sh600754,sz300630,sz300298" );
xhr.send();
}, false );
	</script>
</head>
	<body>
	</body>
</html>

written by ocean

11月 09

新购一台阿里云服务器。今天装了个mysql,记录一下期间遇到的坑。

 

安装就不描述了。本地用Native链接不上

http://blog.wx6.org/2015/434.htm  之前这篇已经介绍过了。

按照正常情况,现在应该轻轻松松连接上了。可是并没有,

出了一个10038的问题,

Telnet检查了链接不上。远程服务器上所有的防火墙都检查过了,没有问题。可是依然连接不上。

网上所有遇到的可能性都尝试了,依然连不上。

 

这时候想到是不是阿里云有什么特俗的地方。  搜了一下 阿里云 3306, 果然有人遇到过这个坑了。

阿里云的安全策略里面是阻断了3306端口,只要加入站规则进去即可。

记录下来,以后不要再犯。

 

随后使用Navicat for Mysql链接出现错误

1045 - Access denied for user 'root'@'X.X.X.X' (using password: YES)

这是需要更改密码

执行登录myql

mysql -h localhost -u root -p

 首先选中mysql表

use mysq;

修改密码

update mysql.user set authentication_string=password('root') where user='root' ;

退出

exit

重启mysql即可

service mysql restart

written by ocean