728x90
반응형

Jenkins에서 k8s로 배포하기 위해 Kubernetes Continuous Deploy 라는 플러그인을 사용하고 있었다.

 

그런데 최신으로 업데이트를 하고 난 뒤 다음과 같은 에러가 발생했다.

ERROR: ERROR: Can't construct a java object for tag:yaml.org,2002:io.kubernetes.client.openapi.models.V1Deployment; exception=Class not found: io.kubernetes.client.openapi.models.V1Deployment
 in 'reader', line 1, column 1:
    apiVersion: apps/v1
    ^

hudson.remoting.ProxyException: Can't construct a java object for tag:yaml.org,2002:io.kubernetes.client.openapi.models.V1Deployment; exception=Class not found: io.kubernetes.client.openapi.models.V1Deployment
 in 'reader', line 1, column 1:
    apiVersion: apps/v1
    ^

	at org.yaml.snakeyaml.constructor.Constructor$ConstructYamlObject.construct(Constructor.java:335)
	at org.yaml.snakeyaml.constructor.BaseConstructor.constructObjectNoCheck(BaseConstructor.java:229)
	at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:219)
	at io.kubernetes.client.util.Yaml$CustomConstructor.constructObject(Yaml.java:337)
	at org.yaml.snakeyaml.constructor.BaseConstructor.constructDocument(BaseConstructor.java:173)
	at org.yaml.snakeyaml.constructor.BaseConstructor.getSingleData(BaseConstructor.java:157)
	at org.yaml.snakeyaml.Yaml.loadFromReader(Yaml.java:490)
	at org.yaml.snakeyaml.Yaml.loadAs(Yaml.java:456)
	at io.kubernetes.client.util.Yaml.loadAs(Yaml.java:224)
	at io.kubernetes.client.util.Yaml.modelMapper(Yaml.java:494)
	at io.kubernetes.client.util.Yaml.loadAll(Yaml.java:272)
	at com.microsoft.jenkins.kubernetes.wrapper.KubernetesClientWrapper.apply(KubernetesClientWrapper.java:236)
	at com.microsoft.jenkins.kubernetes.command.DeploymentCommand$DeploymentTask.doCall(DeploymentCommand.java:172)
	at com.microsoft.jenkins.kubernetes.command.DeploymentCommand$DeploymentTask.call(DeploymentCommand.java:124)
	at com.microsoft.jenkins.kubernetes.command.DeploymentCommand$DeploymentTask.call(DeploymentCommand.java:106)
	at hudson.FilePath.act(FilePath.java:1163)
	at com.microsoft.jenkins.kubernetes.command.DeploymentCommand.execute(DeploymentCommand.java:68)
	at com.microsoft.jenkins.kubernetes.command.DeploymentCommand.execute(DeploymentCommand.java:45)
	at com.microsoft.jenkins.azurecommons.command.CommandService.runCommand(CommandService.java:88)
	at com.microsoft.jenkins.azurecommons.command.CommandService.execute(CommandService.java:96)
	at com.microsoft.jenkins.azurecommons.command.CommandService.executeCommands(CommandService.java:75)
	at com.microsoft.jenkins.azurecommons.command.BaseCommandContext.executeCommands(BaseCommandContext.java:77)
	at com.microsoft.jenkins.kubernetes.KubernetesDeploy.perform(KubernetesDeploy.java:42)
	at jenkins.tasks.SimpleBuildStep.perform(SimpleBuildStep.java:112)
	at hudson.tasks.BuildStepCompatibilityLayer.perform(BuildStepCompatibilityLayer.java:78)
	at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:20)
	at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:741)
	at hudson.model.Build$BuildExecution.build(Build.java:206)
	at hudson.model.Build$BuildExecution.doRun(Build.java:163)
	at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:504)
	at hudson.model.Run.execute(Run.java:1894)
	at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
	at hudson.model.ResourceController.execute(ResourceController.java:97)
	at hudson.model.Executor.run(Executor.java:428)
Caused by: hudson.remoting.ProxyException: org.yaml.snakeyaml.error.YAMLException: Class not found: io.kubernetes.client.openapi.models.V1Deployment
	at org.yaml.snakeyaml.constructor.Constructor.getClassForNode(Constructor.java:664)
	at org.yaml.snakeyaml.constructor.Constructor$ConstructYamlObject.getConstructor(Constructor.java:322)
	at org.yaml.snakeyaml.constructor.Constructor$ConstructYamlObject.construct(Constructor.java:331)
	... 33 more
ERROR: Kubernetes deployment ended with HasError

해당 플러그인 깃헙 이슈에서 찾아보니 다운그레이드를 하면 된다고 했지만

 

막상 시도를 해보니 의존성으로 인하여 모든 플러그인들을 다운그레이드를 해야했다.

 

그래서 다른 방법을 찾다가 Jackson 2 API에서 snakeyaml 에 대한 의존성을 추가해서 발생한 문제라는 것을 알게되었다.

 

이를 해결하기 위해 다음 부분을 주석하여 빌드한 뒤 jenkins에 설치해보니 에러없이 잘 동작하는 것을 확인할 수 있었다.

 

github.com/jenkinsci/jackson2-api-plugin/blob/master/pom.xml#L149-L164

...
    <dependency>
      <groupId>com.fasterxml.jackson.dataformat</groupId>
      <artifactId>jackson-dataformat-yaml</artifactId>
      <version>${jackson.version}</version>
      <exclusions>
        <exclusion>
          <groupId>org.yaml</groupId>
          <artifactId>snakeyaml</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

    <dependency>
      <groupId>io.jenkins.plugins</groupId>
      <artifactId>snakeyaml-api</artifactId>
    </dependency>
 ...

 

참고 문헌

  1. plugins.jenkins.io/kubernetes-cd/

  2. https://github.com/jenkinsci/kubernetes-cd-plugin/issues/134

  3. https://github.com/jenkinsci/jackson2-api-plugin

반응형
728x90
반응형

로그를 쌓는데 Logstash에서 간헐적으로 OOM 에러가 발생했었다.

[ERROR][logstash.pipeline ] Exception in pipelineworker, the pipeline stopped processing new events, please check your filter configuration and restart Logstash. {:pipeline_id=>"mds", "exception"=>"Java heap space", "backtrace"=>["org.jruby.util.ByteList.<init>(ByteList.java:92)", "org.jruby.util.ByteList.dup(ByteList.java:328)", "org.jruby.util.ByteList.dup(ByteList.java:300)", "org.jruby.RubyString.doClone(RubyString.java:1346)", "org.logstash.Cloner.deep(Cloner.java:25)", "org.logstash.Cloner.deepMap(Cloner.java:65)", "org.logstash.Cloner.deep(Cloner.java:21)", "org.logstash.Event.clone(Event.java:310)", "org.logstash.ext.JrubyEventExtLibrary$RubyEvent.rubyClone(JrubyEventExtLibrary.java:147)", "org.logstash.ext.JrubyEventExtLibrary$RubyEvent.rubyClone(JrubyEventExtLibrary.java:142)", "java.base/java.lang.invoke.DirectMethodHandle$Holder.invokeSpecial(DirectMethodHandle$Holder)", "java.base/java.lang.invoke.LambdaForm$MH/0x00000008406a3440.invoke(LambdaForm$MH)", "java.base/java.lang.invoke.DelegatingMethodHandle$Holder.delegate(DelegatingMethodHandle$Holder)", "java.base/java.lang.invoke.LambdaForm$MH/0x000000084069e840.guard(LambdaForm$MH)", "java.base/java.lang.invoke.DelegatingMethodHandle$Holder.delegate(DelegatingMethodHandle$Holder)", "java.base/java.lang.invoke.LambdaForm$MH/0x000000084069e840.guard(LambdaForm$MH)", "java.base/java.lang.invoke.Invokers$Holder.linkToCallSite(Invokers$Holder)", "usr.share.logstash.vendor.bundle.jruby.$2_dot_5_dot_0.gems.logstash_minus_filter_minus_split_minus_3_dot_1_dot_7.lib.logstash.filters.split.RUBY$block$filter$1(/usr/share/logstash/vendor/bundle/jruby/2.5.0/gems/logstash-filter-split-3.1.7/lib/logstash/filters/split.rb:88)", "java.base/java.lang.invoke.DirectMethodHandle$Holder.invokeStatic(DirectMethodHandle$Holder)", "java.base/java.lang.invoke.LambdaForm$MH/0x0000000841005040.invoke(LambdaForm$MH)", "java.base/java.lang.invoke.Invokers$Holder.invokeExact_MT(Invokers$Holder)", "org.jruby.runtime.CompiledIRBlockBody.yieldDirect(CompiledIRBlockBody.java:146)", "org.jruby.runtime.BlockBody.yield(BlockBody.java:114)", "org.jruby.runtime.Block.yield(Block.java:165)", "org.jruby.RubyArray.each(RubyArray.java:1792)", "java.base/java.lang.invoke.LambdaForm$DMH/0x000000084069ac40.invokeVirtual(LambdaForm$DMH)", "java.base/java.lang.invoke.LambdaForm$MH/0x00000008406b3440.invoke(LambdaForm$MH)", "java.base/java.lang.invoke.LambdaForm$MH/0x00000008406c2840.guardWithCatch(LambdaForm$MH)", "java.base/java.lang.invoke.LambdaForm$MH/0x00000008406c3440.invoke(LambdaForm$MH)", "java.base/java.lang.invoke.DelegatingMethodHandle$Holder.delegate(DelegatingMethodHandle$Holder)", "java.base/java.lang.invoke.LambdaForm$MH/0x0000000840674040.guard(LambdaForm$MH)", "java.base/java.lang.invoke.DelegatingMethodHandle$Holder.delegate(DelegatingMethodHandle$Holder)"], :thread=>"#<Thread:0x33a1a707 sleep>"}
[ERROR][org.logstash.Logstash ] java.lang.OutOfMemoryError: Java heap space
[WARN ][logstash.pipeline ] CAUTION: Recommended inflight events max exceeded! Logstash will run with up to 16000 events in memory in your current configuration. If your message sizes are large this may cause instability with the default heap size. Please consider setting a non-standard heap size, changing the batch size (currently 2000), or changing the number of pipeline workers (currently 8) {:pipeline_id=>"mds", :thread=>"#<Thread:0x705f801 run>"}

처음에는 JVM 옵션을 기본 설정인 -Xms1g -Xmx1g 로 하고 있어 이를 늘려서 재시작을 했다.

 

하지만 곧 다시 에러가 발생하면서 로그를 더이상 받지 못했다.

 

그래서 Kafka Input 설정 중에 max_poll_records 를 변경하면서 모니터링했다.

 

몇 시간 동안 잘 되는가 싶더니 곧 에러가 나더니 다시 로그 수집을 못하고 있었다.

 

filter에서 사용하는 부분을 검사하다 이번에 추가된 split이 문제가 있는 것 같아 구글링을 했다.

 

구글링을 해보니 해당 플러그인에 메모리 누수 문제가 발생하는 것 같았다.

 

그래서 이를 대체할 방법을 찾다가 다음과 같이 해보라는 글을 보고 따라해봤다.

def register(params)
    @field = params['field']
    @target = params['target']
end

def filter(event)
    data = event.get(@field)
    event.remove(@field)
    a = []
    data.each { |x|
        e = event.clone
        e.set(@target, x)
        a << e
    }
    a
end
json {
    source => "message"
    remove_field => [ "message" ]
}
ruby {
    path => '/my/path/splitData.rb'
    script_params => { field => "data" target => "data" }
}

split을 변경한 이후로 메모리 누수로 인하여 로그 수집이 중단되는 현상이 나오진 않았다.

 

참고 문헌

  1. https://github.com/logstash-plugins/logstash-filter-split/issues/35

  2. https://discuss.elastic.co/t/how-to-split-into-multiple-events-dynamically-for-a-given-json-tried-from-various-question-in-forums/167745/11

반응형
728x90
반응형

Logstash 부하로 인하여 Elastic Search에 업데이트가 안되고 있었다.

 

그래서 부랴부랴 특정 토픽들을 제외하여 급한 로그들을 처리했다.

 

그런데 일부 로그들을 파싱하는 과정에서 시간 정보를 현재 시간으로 쓰는 경우가 있었다.

 

시간 정보를 따로 갖고는 있었는데 해당 필드로 처리하고 있지 않고 있었다.

 

이것을 해결하기 위한 방법을 찾아보니 _update_by_query 를 사용하면 된다고 하여 시도해보았다.

 

처음엔 인덱스 전부를 업데이트해보았으나 너무 오래 걸렸다.

 

그래서 특정 시간대의 로그만 처리하기로 했고 다음과 같이 데이터를 보내 해결할 수 있었다.

{
  "script": {
    "lang": "painless",
    "source": "ctx._source['@timestamp'] = ctx._source.time"
  },
  "query": {
    "bool": {
        "must": [
            {
                "exists": {
                    "field": "time"
                }
            },
            {
                "range": {
                    "@timestamp": {
                        "time_zone": "+09:00",        
                        "gte": "2020-11-20T21:25:00", 
                        "lte": "2020-11-20T21:30:00"                  
                    }
                }
            }
        ]
    }
  }
}

 

참고 문헌

  1. https://stackoverflow.com/questions/55570214/how-do-i-overwrite-the-timestamp-field-with-another-field-in-elasticsearch

  2. https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update-by-query.html

  3. https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html

  4. https://www.elastic.co/guide/en/elasticsearch/reference/current/compound-queries.html

반응형
728x90
반응형

앱에서 현재 화면이 어떤 방향에 알아낼 필요가 있어

 

Dimensions 의 width, height 값으로 방향을 알아내 화면이 전환을 적용하고 있었다.

 

잘 사용하고 있었는데 React Native 0.63.0 으로 버전업을 하면서 원하는 대로 동작하지 않았다.

 

깃헙 이슈에서 찾아보니 버그로 안드로이드에서만 제대로된 값을 못가져오고 있었다.

 

0.63.3에서도 아직 해당 버그가 수정되지 않아 0.62 버전으로 앱을 만들어 사용하고 있다.

 

참고 문헌

  1. reactnative.dev/docs/dimensions
  2. github.com/facebook/react-native/issues/29323
반응형

+ Recent posts