<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>sunken_ahn.log</title>
        <link>https://velog.io/</link>
        <description>초보 개발자</description>
        <lastBuildDate>Mon, 11 Jul 2022 05:57:47 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. sunken_ahn.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/sunken_ahn" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[카프카 외부연결]]></title>
            <link>https://velog.io/@sunken_ahn/%EC%B9%B4%ED%94%84%EC%B9%B4-%EC%99%B8%EB%B6%80%EC%97%B0%EA%B2%B0</link>
            <guid>https://velog.io/@sunken_ahn/%EC%B9%B4%ED%94%84%EC%B9%B4-%EC%99%B8%EB%B6%80%EC%97%B0%EA%B2%B0</guid>
            <pubDate>Mon, 11 Jul 2022 05:57:47 GMT</pubDate>
            <description><![CDATA[<p>외부 컴퓨터로 podman으로 컨테이너를 통해 카프카를 돌리고 테스트를 위해 접속할려고 하니 이런 메세지가 출력되면서 안되고 있었다.</p>
<p><img src="https://velog.velcdn.com/images/sunken_ahn/post/0e4b65ca-f725-446b-9e68-c415d0568d87/image.png" alt=""></p>
<p>혹시나 해당 소스코드 혹은 라이브러리가 문제인가 해서 카프카를 통해 프로듀서 생성을 시도하니, 이번에도 안되고 있었다.
<img src="https://velog.velcdn.com/images/sunken_ahn/post/69247dc3-da80-4025-8b40-4cc6e45a4387/image.png" alt=""></p>
<p>이래서 자료를 찾아보니, 카프카의 설정 파일중 server.properties에서 listeners,advertised.listeners 두가지의 바인딩 설정값이 있는데, 외부 바인딩 설정값인 avertieed.listeners값이 미설정이면 호스트를 기준으로 바인딩된다고한다. 그렇기에 averieed.listeners 값을 외부 접속에 맞게 설정해야 작동이 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[leetcode 121 문제 (최대 부분 배열)]]></title>
            <link>https://velog.io/@sunken_ahn/leetcode-121-%EB%AC%B8%EC%A0%9C</link>
            <guid>https://velog.io/@sunken_ahn/leetcode-121-%EB%AC%B8%EC%A0%9C</guid>
            <pubDate>Fri, 08 Jul 2022 12:12:44 GMT</pubDate>
            <description><![CDATA[<p><a href="https://leetcode.com/problems/best-time-to-buy-and-sell-stock/">121. Best Time to Buy and Sell Stock</a><br>해당 문제의 요구사항을 분석하자면.  </p>
<ul>
<li>무작위로 숫자배열이 할당 된다. </li>
<li>해당 배열에서 최소값 x 선정한다</li>
<li>최댓값 y를 선정하되, 해당 인덱스를 x의 인덱스보다 높은 값이여야한다.</li>
<li>y-x의 값이 최대일때를 구하라.</li>
</ul>
<p>대략적으로 설명하면 되도록 최솟값에 사서 비쌀때 팔아  최대한 많은 이득을 얻을수 있는 시기를 구하는 알고리즘 문제이다.  </p>
<p>처음엔 몇시간정도 &quot;이것은 마치 주식처럼 저점에 사셔 고점에 파는 그런건가?&quot; 그럼 그래프같은걸 구현해서 계산하는건가? 라고 생각하면서 고민하다가, 알고리즘 초급 문제에 그런것까진 아니라고 생각하곤 예전에 알고리즘 관련 책에서 최대 부분 배열을 봤던걸 생각하여, 그걸로 해결하기로 했다. </p>
<p>책에는 4가지 방식이 있었는데, 그중 제일 성능이 좋은 O(n) 알고리즘으로 작성하여 제출하였다.</p>
<pre><code class="language-c++">#include&lt;algorithm&gt;

class Solution {
public:
    int maxProfit(vector&lt;int&gt;&amp; prices) {
        vector&lt;int&gt; buf;

        int pre = prices[0];

        for(int index = 1;index &lt; prices.size();index++) {
            buf.push_back(prices[index] - pre);
            pre = prices[index];
        }
        int sum = 0;
        int res = 0;
        for(auto &amp;data :buf) {
            sum = max(data,data + sum);
            res = max(res,sum);
        }
        return res;
    }
};</code></pre>
<p>이 알고리즘은 카데인 알고리즘이라고 불리고 있으며 동적 프로그래밍을 이용한 알고리즘인데, 어떤 배열의 부분배열의 합이  S[n]일때, S[n]의 최대 부분 배열은 (S[1],S[2],...,S[n-1])중 하나다 라는 공식을 이용하는 알고리즘이다.  </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[리시버 있는 함수 리터럴 유용한 사용]]></title>
            <link>https://velog.io/@sunken_ahn/%EB%A6%AC%EC%8B%9C%EB%B2%84-%EC%9E%88%EB%8A%94-%ED%95%A8%EC%88%98-%EB%A6%AC%ED%84%B0%EB%9F%B4-%EC%9C%A0%EC%9A%A9%ED%95%9C-%EC%82%AC%EC%9A%A9</link>
            <guid>https://velog.io/@sunken_ahn/%EB%A6%AC%EC%8B%9C%EB%B2%84-%EC%9E%88%EB%8A%94-%ED%95%A8%EC%88%98-%EB%A6%AC%ED%84%B0%EB%9F%B4-%EC%9C%A0%EC%9A%A9%ED%95%9C-%EC%82%AC%EC%9A%A9</guid>
            <pubDate>Sat, 04 Jun 2022 15:35:13 GMT</pubDate>
            <description><![CDATA[<h3 id="계기">계기</h3>
<p>코틀린으로 코딩하는도중 예전에 쓰던 exposed 프레임워크의 코드줄에서 궁금증이 생겼는데.</p>
<pre><code class="language-{.kt}">import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.transaction

object Users : Table() {
    ...
    val name = varchar(&quot;name&quot;, length = 50)
    ...
}
transaction {
    ....
    ....
    Users.update({ Users.name eq &quot;city&quot;}) {
        it[name] = &quot;bob&quot;
    }
}</code></pre>
<p>이라는 코드줄이 있다고 할때, User 싱글톤 객체에 name에 infix 함수인 eq가 있다. 그럼 이걸 update함수 밖에서 
써도 될까에서 시작해서 그렇게 작성해서 컴파일 해봤는데.</p>
<pre><code class="language-{.kt}">import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.transaction

object Users : Table() {
    ...
    val name = varchar(&quot;name&quot;, length = 50)
    ...
}
transaction {
    ....
    ....
    val exist = Users.name eq &quot;city&quot;
    Users.update({ exist }) {
        it[name] = &quot;bob&quot;
    }
}


/*
e: main.kt: (13, 32): Unresolved reference: eq
*/</code></pre>
<p>이러한 에러가 나왔다. 분명 update안에는 컴파일이 됬는데 밖에서 사용하면 해당 함수는 없다고 에러가 나온다.
그래서 찾아본 결과 코틀린의 확장함수랑 관련된걸 알게 됬다.</p>
<pre><code>저 에러를 해결하는 법은 import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq 추가하면 된다.</code></pre><h3 id="본문-및-설명">본문 및 설명</h3>
<p>우선 사람의 이름과 나이를 출력하는 프로그램을 프로그래밍 한다고 치자.</p>
<pre><code class="language-{.kt}">open class Person {
    internal var name : String = &quot;&quot;
    internal var age : Int = 0
}</code></pre>
<p>단순하게 사람을 추상화한 클래스이다. 이것을 빌더패턴을 사용하는 방식으로 작성한다고 치자.
그래서 평소에 다른언어에서 하던 방식으로 작성하였다.</p>
<pre><code class="language-{.kt}">package com.example.kotlinTest.hello

class PersonBuilder(val person: Person) {

    fun name(n : String) :PersonBuilder {
        this.person.name = n
        return this
    }
    fun age(a : Int) : PersonBuilder {
        this.person.age = a
        return this
    }
    fun build() {
        print(&quot;hi my name is : ${person.name}\n&quot;)
        println(&quot;my age is : ${person.age}\n&quot;)
    }
}</code></pre>
<pre><code class="language-{.kt}">import com.example.kotlinTest.hello.*

fun main() {
    var builder = PersonBuilder(Person())
    builder
        .name(&quot;ahn&quot;)
        .age(25)
        .build()
}</code></pre>
<p>이렇게 작성하고보니 비록 본인의 코딩실력이 좋지않아도 이정도면 괜찮지 않을까 싶었지만, 
사실 코틀린은 다른언어보다 지원하는 문법들이 많았고 이것을 활용하면 더 보기 좋은 코드를 작성할수 있다고 한다. 
그래서 찾아보니 infix 함수랑 리시버 함수가 있다고 한다.</p>
<p>해당 함수들의 설명은 공식 문서에 가면 있으니 먼저 보고 오는게 좋다.<br><em>infix 함수 : <a href="https://kotlinlang.org/docs/functions.html#infix-notation">https://kotlinlang.org/docs/functions.html#infix-notation</a></em><br><em>리시버 함수 : <a href="https://kotlinlang.org/docs/lambdas.html#function-literals-with-receiver">https://kotlinlang.org/docs/lambdas.html#function-literals-with-receiver</a></em>  </p>
<p>이것들을 활용하면 위의 update함수처럼 별도의 import가 없으면 안에서는 사용할수 있지만, 밖에서는 사용못하게 할수도 있다.
이제 infix,리시버들을 활용한 소스코드이다.</p>
<pre><code class="language-{.kt}">package com.example.kotlinTest.hello
/*
본래 해당 객체안의 확장 함수들은, PersonMethod를 임포트 안하면 사용이 안된다.
*/
object PersonMethod {
    infix fun Person.age(other : Int) {
        this.age = other
    }
    infix fun Person.name(other : String) {
        this.name = other
    }

}
/*
block 변수로 리시터 함수 리터럴을 받게 됨으로써, PersonMethod안의 함수들이 사용가능해 진다.
*/
fun build(person: Person,block : PersonMethod.(Person) -&gt; Unit) {
    PersonMethod.block(person)
    print(&quot;hi my name is : ${person.name}\n&quot;)
    println(&quot;my age is : ${person.age}\n&quot;)
}</code></pre>
<pre><code class="language-{.kt}">import com.example.kotlinTest.hello.build
import com.example.kotlinTest.hello.Person

fun main() {
    build(Person()) {
        it name &quot;ahn&quot;
        it age  25
    }
}</code></pre>
<p>예시가 좋지 못하지만, 이렇게 소스코드를 작성할수가 있다. 즉 PersonMethod 객체를 임포트 안해도 Person 확장 함수를 사용할수 있다.</p>
<pre><code>위 계기의 소스코드 해결법처럼 확장함수가 정의된 import com.example.kotlinTest.hello.PersonMethod를  추가하면 밖에서도 사용이 가능하다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[싱글,멀티 스레드 파일 저장 성능]]></title>
            <link>https://velog.io/@sunken_ahn/%EC%8B%B1%EA%B8%80%EB%A9%80%ED%8B%B0-%EC%8A%A4%EB%A0%88%EB%93%9C-%ED%8C%8C%EC%9D%BC-%EC%A0%80%EC%9E%A5-%EC%84%B1%EB%8A%A5</link>
            <guid>https://velog.io/@sunken_ahn/%EC%8B%B1%EA%B8%80%EB%A9%80%ED%8B%B0-%EC%8A%A4%EB%A0%88%EB%93%9C-%ED%8C%8C%EC%9D%BC-%EC%A0%80%EC%9E%A5-%EC%84%B1%EB%8A%A5</guid>
            <pubDate>Mon, 23 May 2022 08:26:20 GMT</pubDate>
            <description><![CDATA[<p>프로그래밍 하는 도중 파일을 입출력 코드를 작성하는 상황이 있었는데, 여기서 &quot;파일 저장 성능이 싱글 스레드 그리고 멀티 스레드중 어느것이 나을까?&quot;라고 궁금중이 생겨서, 따로 코드를 작성하고 테스트했던것을 적어볼려고 한다.<br>우선 나는 어느것이 성능이 좋을지 생각하면서  어떤 프로그램 요구서를 생각하고, 그것에 따라서 작성해보았다.</p>
<h3 id="프로그램-계획">프로그램 계획</h3>
<h5 id="요구--랜덤-해쉬값을-생성후-해당값을-파일이름-그리고-파일내용으로-작성하여-특정폴더에-저장한다">요구 : 랜덤 해쉬값을 생성후, 해당값을 파일이름 그리고 파일내용으로 작성하여 특정폴더에 저장한다.</h5>
<ol>
<li>프로그램은 싱글,멀티스레드 선택값,폴더경로 그리고 파일 생성 갯수값을 인수로 입력받는다</li>
<li>해쉬값을 랜덤으로 생성한다</li>
<li>해당값으로 파일명으로 해서 생성후, 해당 파일에 해당값을 저장</li>
<li>이 행동을 생성 갯수값만큼 반복한다</li>
<li>반복이 완료후의 시간을 측정하고, 출력한다</li>
<li>프로그램 종료</li>
</ol>
<p>그리고 해당 요구서를 토대로 코틀린으로 작성해보았다.</p>
<pre><code class="language-{.kt}">//main.kt

//메인 함수
import java.lang.Exception
import kotlin.system.measureTimeMillis

fun main(args: Array&lt;String&gt;) {

    val c = args.first().toInt() // 1 : 멀티스레드,2: 싱글스레드
    val root = args[1] // 폴더 경로
    val count = args[2].toInt() // 파일 생성 갯수
    val fIO : IoTest = when(c) {
        1 -&gt; AsyncFileIO(count,root,4)// 스레드는 4개 생성후 사용
        2 -&gt; NonFileIO(count,root)
        else -&gt; throw Exception(&quot;not 1 and 2&quot;)
    }

    val time = measureTimeMillis {
        fIO.run()
    }

    println(&quot;time : ${time}(ms)&quot;)
}</code></pre>
<pre><code class="language-{.kt}">//IoTest.kt

//추상클래스
abstract class IoTest
constructor(protected val maxCount : Int,protected val root : String) {
    abstract fun run()
}</code></pre>
<h2 id="싱글-스레드-코드">싱글 스레드 코드</h2>
<pre><code class="language-{.kt}">//NonFileIO.kt
//싱글 스레드 작동 객체

import kotlin.io.*
import java.io.File
import java.nio.charset.Charset
import java.util.UUID
import java.nio.file.Paths



class NonFileIO(maxCount: Int, root: String) : IoTest(maxCount, root) {
    override fun run() {
        var i = 0;
        var random_uuid = UUID.randomUUID().toString()

        while(i &lt; maxCount) {
            var file = File(Paths.get(root,random_uuid).toString())
            file.createNewFile()
            file.writeText(random_uuid, Charset.defaultCharset())
            random_uuid = UUID.randomUUID().toString()
            i++
        }
    }

}</code></pre>
<h5 id="그림으로-간단하게-표현">그림으로 간단하게 표현</h5>
<p><img src="https://velog.velcdn.com/images/sunken_ahn/post/caaf2d06-863c-4555-99d4-8ef451e3c17b/image.png" alt=""></p>
<h2 id="멀티스레드-코드">멀티스레드 코드</h2>
<pre><code class="language-{.kt}">//AsyncFileIO.kt
//멀티스레드 작성 객체
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import java.io.File
import java.nio.charset.Charset
import java.nio.file.Paths
import java.util.*

class AsyncFileIO(
        maxCount: Int, root: String,private val tCount : Int) : IoTest(maxCount, root) {


    private suspend fun createWorker (channel : Channel&lt;String&gt;) {
        for(i in 1..tCount) {
            //해당 코드를 사용하면 자바내부에 스레드가 생성된다.
            CoroutineScope(Dispatchers.IO).launch {
                while(!channel.isClosedForSend) {
                    if(channel.isEmpty)continue
                    val msg = channel.receive()
                    var file = File(Paths.get(root,msg).toString())
                    file.createNewFile()
                    file.writeText(msg, Charset.defaultCharset())
                }
            }
        }

    }

    override  fun run() : Unit = runBlocking {
        val channel = Channel&lt;String&gt;()


        val job = async {
            createWorker(channel)
        }
        for(i in 1..maxCount) {
            var random_uuid = UUID.randomUUID().toString()
            channel.send(random_uuid)
        }
        channel.close()
        job.await()
    }



}</code></pre>
<h5 id="그림으로-간단하게-표현-1">그림으로 간단하게 표현</h5>
<p><img src="https://velog.velcdn.com/images/sunken_ahn/post/5bdf76a3-4d7a-4334-83cd-a9452df86e90/image.png" alt=""></p>
<p>이것을 토대로 10000개의 파일을 생성하는 테스트를 해본결과...  </p>
<h3 id="결과창">결과창</h3>
<p><img src="https://velog.velcdn.com/images/sunken_ahn/post/eb6532eb-a43b-4c64-bda8-09d47b37239e/image.PNG" alt=""></p>
<table>
<thead>
<tr>
<th>방식</th>
<th>시간표</th>
</tr>
</thead>
<tbody><tr>
<td>싱글스레드</td>
<td>68.953s</td>
</tr>
<tr>
<td>멀티스레드</td>
<td>46.261s</td>
</tr>
</tbody></table>
<p>이렇게 꽤 차이 나는 결과를 알게되었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[간단하게 쓸 홈서버 세팅  - 1 ]]></title>
            <link>https://velog.io/@sunken_ahn/%EA%B0%84%EB%8B%A8%ED%95%98%EA%B2%8C-%EC%93%B8-%ED%99%88%EC%84%9C%EB%B2%84-%EC%84%B8%ED%8C%85-1</link>
            <guid>https://velog.io/@sunken_ahn/%EA%B0%84%EB%8B%A8%ED%95%98%EA%B2%8C-%EC%93%B8-%ED%99%88%EC%84%9C%EB%B2%84-%EC%84%B8%ED%8C%85-1</guid>
            <pubDate>Wed, 11 May 2022 11:47:47 GMT</pubDate>
            <description><![CDATA[<h1 id="목차">목차</h1>
<ul>
<li><a href="#%EC%84%9C%EB%A1%A0">0.서론</a></li>
<li><a href="#podman-%EC%84%A4%EC%B9%98">1. podman 설치</a></li>
<li><a href="#%EC%9D%B4%EB%AF%B8%EC%A7%80-pull-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EC%8B%A4%ED%96%89">2. 이미지 pull 그리고 컨테이너 실행</a></li>
<li><a href="#btrfs-%ED%8C%8C%ED%8B%B0%EC%85%98">3. btrfs 파티션</a></li>
<li><a href="#%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EC%84%A4%EC%A0%95">4. 컨테이너 설정</a></li>
<li><a href="#%ED%8F%B4%EB%8D%94-%EA%B6%8C%ED%95%9C">5. 폴더 권한</a></li>
<li><a href="#%EB%B0%A9%ED%99%94%EB%B2%BD-%EC%84%A4%EC%A0%95">6. 방화벽 설정</a></li>
<li><a href="#%EC%82%AC%EC%9D%B4%ED%8A%B8-%EC%84%A4%EC%A0%95">7. 사이트 설정</a></li>
</ul>
<h2 id="서론">서론</h2>
<p>노트북으로 프로그래밍 하던 작업물을 다른 컴퓨터로 옮기는데 이메일 또는 sd 카드로 일일히 옮기는게 귀찮아져서 이참에 창고에 보관하던 미니 피씨로 홈서버로 클라우드 스토리지 서버를 돌릴 생각을 하게 되었고, 나중에 다시 세팅할때 까먹지 않고 글로 작성하기로 했다.</p>
<p><strong>실행환경</strong></p>
<ul>
<li>운영체제 : debian 11<h2 id="podman-설치">podman 설치</h2>
데비안 설치직후 실행하면 sudo가 설치가 안되어있으니, 바로 root계정으로 변경하여 사용한다<pre><code class="language-bash">#이 명령어로 root계정으로 변경
su</code></pre>
데비안 공식 저장소에 podman이 있으니 apt로 설치가 된다<pre><code class="language-bash">apt install podman</code></pre>
그후 서비스에 등록을 한다.<pre><code class="language-bash">systemctl enable podman</code></pre>
</li>
<li><strong>etc</strong>
만약 podman를 콘솔창에 쳤는데 해당 프로그램이 없다고 실행이 안되면, <code>echo $PATH</code> 명령어로 PATH 변수 안에 <code>usr/bin</code>이 경로에 포함되었는지 확인후,만약  없으면 <code>etc/profile</code> 수정 혹은 <code>export</code>를 사용해 경로를 추가하면 된다<h2 id="이미지-pull-그리고-컨테이너-실행">이미지 pull 그리고 컨테이너 실행</h2>
사용할 서버는 nextcloud 이다.
그렇기에 해당 이미지를 pull하면 되나, 데비안에서 podman는 도커허브에 있는 대부분의 이미지는 pull이 되지 않는다. 해당 문제를 해결하기 위해선 podman의 저장소 설정파일을 수정하면 된다.</li>
</ul>
<p><strong>에러창</strong>
<img src="https://velog.velcdn.com/images/sunken_ahn/post/0a3bb773-5f0e-4955-b97f-1684fa0e36bb/image.PNG" alt="error message"></p>
<pre><code class="language-bash">#vim /etc/containers/registries.conf.d/shortnames.conf
#`&quot;nextcloud&quot;=&quot;docker.io/library/nextcloud&quot;` 내용 추가 후 저장

#그후 pull명령어를 실행하면 된다.
#podman pull nextcloud</code></pre>
<p>자세한건 <a href="https://github.com/containers/podman/issues/9390">podman issue</a>에 있으니 참고하면 된다.</p>
<h2 id="btrfs-파티션">btrfs 파티션</h2>
<p>nextcloud의 데이터를 저장할 곳을 btrfs 파티션으로 포맷할려면 우선 btrfs-progs를 설치해야한다.</p>
<pre><code class="language-bash">apt install btrfs-progs</code></pre>
<p>그다음 사용할 파티션을 btrfs로 포맷한다.</p>
<pre><code class="language-bash">mkfs.btrfs -d raid1 -m raid1 /dev/sdb[number] /dev/sda[number]</code></pre>
<p>그리고 nextcloud 데이터를 저장할 파티션 하나를 선택후 마운트 한다.</p>
<pre><code>mkdir &#39;사용할 디렉토리 이름&#39;
mount &#39;사용할 파티션 경로&#39; &#39;생성한 디렉토리 이름&#39;</code></pre><p>또는 재시작시 자동으로 마운트를 원한다면 <code>etc/fstab</code> 파일을 수정하면 된다.</p>
<pre><code class="language-bash">#vim /etc/fstab
...
...
...
`파티션 경로` `디렉토리 경로` btrfs defaults 0 0
#이후 저장후,만약 아직 마운트를 안했으면 &#39;systemctl daemon-reload&#39;을 실행해주자</code></pre>
<p>자세한건 <a href="https://help.ubuntu.com/community/Fstab">우분투 위키</a>를 참고하자</p>
<h2 id="컨테이너-설정">컨테이너 설정</h2>
<p>podman 으로 컨테이너를 생성해준다</p>
<pre><code class="language-bash">podman run -d -v &#39;btrfs파티션 마운트 경로&#39;:&#39;컨테이너에서 사용할 디렉토리 경로&#39; -p 8080:80 --name `컨테이너 이름` nextcloud</code></pre>
<p>만약 sqlite를 사용할거면 해당 목차를 스킵하면 된다.</p>
<ul>
<li><h4 id="컨테이너-안에--mysql-설치-및--설정">컨테이너 안에  mysql 설치 및  설정</h4>
</li>
</ul>
<p>mysql 돌리는 방법은 여러가지가 있지만, mysql를 해당 컨테이너만 사용할 생각이기에 그냥 컨테이너안에 설치하는 방향으로 갈것이다.</p>
<pre><code class="language-bash">podman exec -it &#39;컨테이너 이름&#39; bash
#컨테이너 접속후
apt update
apt install net-tools
apt install default-mysql-server</code></pre>
<p>해당 컨테이너 에서는 systemd를 이용한 mysql 실행이 안되니, 다음 명령어를 실행하면 된다</p>
<pre><code class="language-bash">mysql start &amp;
#mysql server 실행 확인
#3306 포트가 열러있으면 성공이다.
netstat -ntlp</code></pre>
<p><strong>etc</strong>
만약 /run/mysqld 관련 에러가 뜨면, <code>mkdir /run/mysqld</code>로 디렉토리 생성 후, 해당 디렉토리를 777 퍼미션 혹은 원하는 권한 및 소유자로 변경하면 해결된다.</p>
<h2 id="폴더-권한">폴더 권한</h2>
<p>현재 컨테이너는 호스트에 있는 파티션 디렉토리를 <a href="https://docs.docker.com/storage/bind-mounts/">바인드 마운트</a> 해서 데이터 디렉토리로 쓸 예정이기에, 별도로 권한도 설정해야한다.
nextcloud 컨테이너는 아파치 + php로 서버가 돌아가는데, 아파치는 데비안에서 www-data계정으로  돌아가게 되었있다. 그렇기에 서버는 www-data계정으로 쓰기,읽기를 시도하는데, 호스트에선 파티션 디렉토리가 root 소유로 되어있다. 그러히게 권한이 안되서 접근이 안된다.</p>
<p>여러 방법이 있겠지만 지금 사용할 방법은 호스트에서 www-data 계정이 있고, 컨테이너의 www-data의 uid가 동일한다는 가정하에, 호스트의 btr파티션 마운트 디렉토리를 www-data 소유를 변경하는걸로 한다.</p>
<pre><code class="language-bash">chown `btrfs 마운트 디렉토리` www-data
#파티션은 770으로 설정
chmod 770 -R `btrfs 마운트 디렉토리`</code></pre>
<h2 id="방화벽-설정">방화벽 설정</h2>
<p>방화벽은 iptables이 아닌 ufw로 설정할것이며,그렇기에  호스트에서 ufw를 설치한 후에 설정하면 된다.</p>
<pre><code class="language-bash">apt install ufw
# 방화벽 설정
ufw allow 22 #ssh 접속이 필요할시
#예시 : ufw aloow from 192.168.100.0/24 to any port 8080
ufw allow from &#39;ip&#39;/&#39;subnet mask&#39; to any port &#39;port number&#39;
#설정 적용, systemctl 시작 프로세스 등록
ufw enable
systemctl enable ufw</code></pre>
<p><strong>etc</strong>
만약 이상태에서 접근이 안되면, 로그창에 이런 메세지가 있는지 확인하자
<img src="https://velog.velcdn.com/images/sunken_ahn/post/f7201db4-41de-4ace-b944-b2154e390158/image.png" alt="error"></p>
<p>보통 ufw는 포워딩은 기본적으로 차단한다. 그렇기에 저런 메세지가 뜨면 etc 설정을 수정하고 다시 적용하면 된다.</p>
<pre><code class="language-bash">#vim /etc/default/ufw
...
...
...
#DROP으로 설정되있는걸 ACCEPT로 변경하자
DEFAULT_FORWARD_POLICY=&quot;ACCEPT&quot;
...
#:wq
#그후 ufw를 리로드 하면된다.
ufw reload
</code></pre>
<p>자세한건 <a href="https://gist.github.com/kimus/9315140">여기</a>를 참고하면 좋을것이다.</p>
<h2 id="사이트-설정">사이트 설정</h2>
<p><img src="https://velog.velcdn.com/images/sunken_ahn/post/9a0637dd-b2c8-4743-a4ba-9ddf9cb78312/image.png" alt=""></p>
<p>이제 ip주소로 서버에 접속하면 화면이 나오고 설정창이 보일거다. 여기서 mysql로 설정을 진행하다가 에러가 날수 있는데, 이때 만약 localhost로 했으면, 그걸 127.0.0.1로 변경하고 설정 하면, 설정 완료후 메인창이 나올것이다.
<img src="https://velog.velcdn.com/images/sunken_ahn/post/b4e113dd-08cb-4fef-910b-75482f259e3a/image.PNG" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[trait를 리턴하는 방법]]></title>
            <link>https://velog.io/@sunken_ahn/trait%EB%A5%BC-%EB%A6%AC%ED%84%B4%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@sunken_ahn/trait%EB%A5%BC-%EB%A6%AC%ED%84%B4%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sun, 01 May 2022 15:11:30 GMT</pubDate>
            <description><![CDATA[<p>러스트로 코딩하던 도중에 트레이드를 리턴해야하는 함수를 만들어야 하는 상황이 있었다.
그래서 go언어를 코딩하는것과 마찬가지로 리턴타입을 트레이드(go언어에선 인터페이스)로 하여 리턴 하는 함수를 작성후 컴파일 해본적이 있었는데 그때의 일을 비슷하게 재현하여 적어볼려고 한다.</p>
<pre><code class="language-go">//go 코드 예시
package main

import &quot;fmt&quot;

type Hi interface {
    hi()
}

type String struct {
    s string
}

func new_hi(s string) Hi {
    return &amp;String{s}
}
func (s *String)hi() {
    fmt.Println(&quot;hi : &quot;s.s)
}

func main() {
    var str = &quot;sunken ahn&quot;
    new_hi(str).hi()
}</code></pre>
<p>이런한 기능을 하는 프로그램을 작성한다고 할때, 이것을 러스트로 재작성할려고 한다.<br>그래서 내 생각대로 러스트 코드를 작성하게 되었다.</p>
<pre><code class="language-rust">//rust 코드 예시
trait Hi {
    fn hi(&amp;self);
}

impl Hi for String {
    fn hi(&amp;self) {
        println!(&quot;hi : {}&quot;,self);
    }
}

fn new_hi(val : String) -&gt; Hi {
    return val;
}

fn main() {
    let name = String::from(&quot;sunken ahn&quot;);
    new_hi(name).hi();
}
</code></pre>
<p>이렇게 작성하고 컴파일 하니 에러메세지가 나타났다.
<img src="https://velog.velcdn.com/images/sunken_ahn/post/b32a6a75-7145-4ee7-97b0-d2fdc57c719f/image.PNG" alt="result">
그래서 처음에는 <strong>이게 왜?</strong> 였다. 해당 에러가 리턴 타입 지정에서 에러가 나왔는데
다른언어들은 원하는 타입을 리턴하고 싶으면 함수에 리턴 타입을 지정하는데 말이다.</p>
<p>그리고 찾아보니, rust의 컴파일 방식 때문인걸 알게 되었다.
러스트는 메모리 안전성을 위해 다른언어들과 다르게 컴파일 단계에서 메모리 관리하고 안전성을 추척한다.
그렇기에 메모리 관리를 위해 변수의 메모리 크기등을 컴파일러가 알아야 하는데, 트레이드는 이른바 일종의 여러 메소드의 묶음박스일뿐, 그 자체가 타입이 아니다. 그렇기에 변수의 메모리 크기의 정보가 없기에, 컴파일러는 해당 함수의 리턴값이 어느정도의 크기인지 알수없기에 컴파일 에러를 보내는것이다.  </p>
<p>그렇기에 다른방식으로 값을 리턴시키면 된다.  </p>
<h4 id="첫번째로-박스라는-러스트의-힙할당-구조체를-사용하여-리턴하는-방법">첫번째로 박스라는 러스트의 힙할당 구조체를 사용하여 리턴하는 방법.</h4>
<p><img src="https://velog.velcdn.com/images/sunken_ahn/post/e1e3ec1b-6fa3-48cd-be7b-82bf3a87b048/image.PNG" alt="second"></p>
<h4 id="두번째로-impl-trait를-리턴-타입으로-적어서-쓰는-방법이다">두번째로 impl trait를 리턴 타입으로 적어서 쓰는 방법이다.</h4>
<p><img src="https://velog.velcdn.com/images/sunken_ahn/post/aeb1aba4-7025-4acd-8d8f-61b84863b726/image.PNG" alt="three"></p>
<h5 id="참고">참고</h5>
<p><a href="https://doc.rust-lang.org/book/ch10-02-traits.html">Traits: Defining Shared Behavior</a>
<a href="https://doc.rust-lang.org/reference/items/traits.html#object-safety">Object Safety</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[몇몇 타입이 구조체의 필드변수를 리턴 못하는 이유]]></title>
            <link>https://velog.io/@sunken_ahn/%EB%AA%87%EB%AA%87-%ED%83%80%EC%9E%85%EC%9D%B4-%EA%B5%AC%EC%A1%B0%EC%B2%B4%EC%9D%98-%ED%95%84%EB%93%9C%EB%B3%80%EC%88%98%EB%A5%BC-%EB%A6%AC%ED%84%B4-%EB%AA%BB%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@sunken_ahn/%EB%AA%87%EB%AA%87-%ED%83%80%EC%9E%85%EC%9D%B4-%EA%B5%AC%EC%A1%B0%EC%B2%B4%EC%9D%98-%ED%95%84%EB%93%9C%EB%B3%80%EC%88%98%EB%A5%BC-%EB%A6%AC%ED%84%B4-%EB%AA%BB%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Fri, 29 Apr 2022 12:01:07 GMT</pubDate>
            <description><![CDATA[<p>코딩하던 도중에, 구조체의 변수값을 리턴하는 함수를 만들던 도중에 있던일을 적을라고 한다.
일단 구조체에 있는 문자열 변수를 읽는 함수를 제작했다 하자.  </p>
<pre><code class="language-rust">
struct A {
    num : u32,
    s : String
}
impl A {
    fn get_string(&amp;self) -&gt; String {
        self.s
    }
/***/
}

fn main() {
    let object = A{num : 0,s : String::from(&quot;&quot;)};
    let _copyS = object.get_string();
/***/
}
</code></pre>
<p>다른 언어에서 작성하던것처럼 문자열의 get기능을 함수로 만들어 놓고 컴파일 해보니 이런 에러가 뜬다.</p>
<pre><code>Compiling playground v0.0.1 (/playground)
error[E0507]: cannot move out of `self.s` which is behind a shared reference
 --&gt; src/main.rs:7:9
  |
7 |         self.s
  |         ^^^^^^ move occurs because `self.s` has type `String`, which does not implement the `Copy` trait

For more information about this error, try `rustc --explain E0507`.
error: could not compile `playground` due to previous error</code></pre><p>아 러스트는 대입이 아닌 이동이니 그런걸수 있겠다고 생각할수 있지만, 정수형으로 함수를 작성하면 정상적으로 작동하는걸 알수있다.</p>
<pre><code class="language-rust">struct A {
    num : u32,
    s : String
}
impl A {
    fn get_u32(&amp;self) -&gt; u32 {
        self.num
    }
/***/
}

fn main() {
    let object = A{num : 0,s : String::from(&quot;&quot;)};
    let _copyS = object.get_u32();
/***/
}
/*
경고창을 나오지만 컴파일 에러는 나오지 않는다.
*/</code></pre>
<p>그래서 찾아보니 Copy라고 복사하고 관련된 트레이드 인데, 해당 트레이드를 구현하는 타입들은 
대입연산자(=)에서 묵시적으로 변수 이동이 아닌 변수 복사가 된다고 한다.<br>즉 u32은 기본적으로 copy트레이드가 구현되 있지만, String 타입은 해당 트레이드 구현이 안되있다, 그래서 
get 함수에서는 값 이동으로 작동하는데, self가 참조형이여서 이동이 안된다고 컴파일 에러가 나는것같다.
그럼 참조형을 안쓰면 되는거 하면?, get함수 호출후에 구조체 사용이 불가능한다는 문제가 있다.</p>
<pre><code class="language-rust">struct A {
    num : u32,
    s : String
}
impl A {
    fn get_string(self) -&gt; String {
        self.s
    }
/***/
}

fn main() {
 let object = A{num : 0,s : String::from(&quot;&quot;)};
    let _copyS = object.get_string();
    println!(&quot;{}&quot;,object.get_string())
/***/
}
/* output
Compiling playground v0.0.1 (/playground)
error[E0382]: use of moved value: `object`
  --&gt; src/main.rs:15:19
   |
13 |  let object = A{num : 0,s : String::from(&quot;&quot;)};
   |      ------ move occurs because `object` has type `A`, which does not implement the `Copy` trait
14 |     let _copyS = object.get_string();
   |                         ------------ `object` moved due to this method call
15 |     println!(&quot;{}&quot;,object.get_string())
   |                   ^^^^^^ value used here after move
   |
note: this function takes ownership of the receiver `self`, which moves `object`
  --&gt; src/main.rs:6:19
   |
6  |     fn get_string(self) -&gt; String {
   |                   ^^^^

For more information about this error, try `rustc --explain E0382`.
error: could not compile `playground` due to previous error
*/</code></pre>
<p>그래서 해결법을 몇시간들어 찾아봤는데, 문자열 타입이 Clone 트레이드(Copy트레이드랑 비슷한 기능) 구현을 지원한다고 한다.
즉 함수에서 clone()를 호출하면 해결된다.</p>
<pre><code class="language-rust">struct A {
    num : u32,
    s : String
}
impl A {
    fn get_string(&amp;self) -&gt; u32 {
        self.s.clone()
    }
/***/
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[배열 생성자와 배열 리터럴 생성 인스턴스의 map 함수 작동 결과]]></title>
            <link>https://velog.io/@sunken_ahn/%EB%B0%B0%EC%97%B4-%EC%83%9D%EC%84%B1%EC%9E%90%EC%99%80-%EB%B0%B0%EC%97%B4-%EB%A6%AC%ED%84%B0%EB%9F%B4-%EC%83%9D%EC%84%B1-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4%EC%9D%98-map-%ED%95%A8%EC%88%98-%EC%9E%91%EB%8F%99-%EA%B2%B0%EA%B3%BC</link>
            <guid>https://velog.io/@sunken_ahn/%EB%B0%B0%EC%97%B4-%EC%83%9D%EC%84%B1%EC%9E%90%EC%99%80-%EB%B0%B0%EC%97%B4-%EB%A6%AC%ED%84%B0%EB%9F%B4-%EC%83%9D%EC%84%B1-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4%EC%9D%98-map-%ED%95%A8%EC%88%98-%EC%9E%91%EB%8F%99-%EA%B2%B0%EA%B3%BC</guid>
            <pubDate>Tue, 26 Apr 2022 13:33:52 GMT</pubDate>
            <description><![CDATA[<h3 id="예시-코드">예시 코드</h3>
<pre><code class="language-js">const array1 = new Array(2);
const array2 = [undefined,undefined];
const map1 = array1.map(x =&gt; 1 * 2);
const map2 = array2.map(x =&gt; 1 * 2);

console.log(array1);
console.log(array2);
console.log(map1);
console.log(map2);
//output
&gt; Array [undefined, undefined]
&gt; Array [undefined, undefined]
&gt; Array [undefined, undefined]
&gt; Array [2, 2]</code></pre>
<h3 id="본문">본문</h3>
<p>자바스크립트의 array 생성자는 길이 파라미터만 넘겨줬을경우, 길이 만큼 배열을 생성하지만 배열 속에 값은 undefined, 정수, 문자열도 아닌 빈값으로 존재한다. 하지만 출력시에는 undefiend로 출력된다. 그리고 map 메서드는 접근한 인덱스가 빈값이면, 결과 배열의 해당 인덱스도 빈값으로 저장한다.</p>
<p>그렇기에 저런 결과물이 나온다.</p>
<h5 id="참고">참고</h5>
<ul>
<li><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/Array">https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/Array</a></li>
<li><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/map">https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/map</a></li>
<li><a href="https://stackoverflow.com/questions/5501581/javascript-new-arrayn-and-array-prototype-map-weirdness">https://stackoverflow.com/questions/5501581/javascript-new-arrayn-and-array-prototype-map-weirdness</a></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>