AWS Glue는 유용한 서비스 이지만 개발이 간편하지 않다. 그 이유는 Spark를 Serverless로 사용하는 서비스이며, Spark를 Glue라는 이름으로 감쌌기 때문에 내부 구조를 명확하게 이해하는게 어렵기 때문이다.
일반적인 상황이라면 공식 문서로 충분하다. https://docs.aws.amazon.com/ko_kr/glue/latest/dg/aws-glue-programming-etl-libraries.html
하지만, 사설 인증서가 개입되면 이야기는 달라진다. 각 시스템의 상황에 따라서 사설인증서를 이용해야만 VPN을 통한 AWS 접근이 가능하다던지, AWS의 S3 버킷의 접속시 443 port를 통한 TLS 프로토콜로만 제한하는 경우 등이 있을 수 있다.
이 문제를 해결하기 위한 정보가 충분하지 않아서 시간이 많이 걸렸다. 하지만 여러가지 노력을 통해서 정답을 얻을 수 있었으니 문제를 겪고 있는 개발자들에게 도움이 되면 좋겠다. (결정적 단서를 찾아준 ChatGPT도 답을 찾아 가는데 많은 단서를 필요로 했다.)
--
그리고 우리가 테스트하려고 하는 script는 공식 문서에 나온 아래 파일이다.
import sys
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.job import Job
from awsglue.utils import getResolvedOptions
class GluePythonSampleTest:
def __init__(self):
params = []
if '--JOB_NAME' in sys.argv:
params.append('JOB_NAME')
args = getResolvedOptions(sys.argv, params)
self.context = GlueContext(SparkContext.getOrCreate())
self.job = Job(self.context)
if 'JOB_NAME' in args:
jobname = args['JOB_NAME']
else:
jobname = "test"
self.job.init(jobname, args)
def run(self):
dyf = read_json(self.context, "s3://awsglue-datasets/examples/us-legislators/all/persons.json")
dyf.printSchema()
self.job.commit()
def read_json(glue_context, path):
dynamicframe = glue_context.create_dynamic_frame.from_options(
connection_type='s3',
connection_options={
'paths': [path],
'recurse': True
},
format='json'
)
return dynamicframe
if __name__ == '__main__':
GluePythonSampleTest().run()
sc
객체를 따로 선언한 뒤,_jsc.hadoopConfiguration()
을 이용한 것이다. 하지만 아래 방법은 모두 작동하지 않았다. Glue의 로컬 이미지인 만큼 아마도 기본적으로는 이미 적용이 되어있었던 것 같다. 특히 검색을 하다 보면 region을 지정하라는 조언이 많은데, 내 경우는 pycharm에서 이미 aws credential과 config를 들고 들어가 수 있는 plugin을 사용했기 때문에 이로 인해 문제가 해결되지는 않았다. 하지만 이렇게 프로그래밍 방식으로 접근하는 것은 좋은 시도이다.self.sc = SparkContext.getOrCreate()
self.sc._jsc.hadoopConfiguration().set("fs.s3a.connection.ssl.enabled", "true")
self.sc._jsc.hadoopConfiguration().set("fs.s3a.ssl.channel.mode", "Default")
self.sc._jsc.hadoopConfiguration().set("fs.s3a.ssl.cacert.file", "/etc/ssl/certs/사설인증서.crt")
self.sc._jsc.hadoopConfiguration().set("fs.s3a.endpoint", "s3.ap-northeast-2.amazonaws.com")
self.sc._jsc.hadoopConfiguration().set("fs.s3a.impl", "org.apache.hadoop.fs.s3a.S3AFileSystem")
self.sc._jsc.hadoopConfiguration().set("fs.s3a.connection.ssl.debug","true")
keytool -import -trustcacerts -keystore /home/glue_user/.certs/container_certs/keystore.jks -storepass changeit -alias mycert -noprompt -file /home/glue_user/aws_helper/사설인증서.crt
여기서 중요한 것은 keystore를 저장하는 위치이다. aws glue 이미지에서는 /home/glue_user/.certs/container_certs/
이곳이 default이다. 최초에 이 이미지 docker 컨테이너에 진입하게 되면 localhost.jks 라는 self-signed certificate를 만드는 것을 확인할 수도 있다. 이후에 이 과정을 자동화 하기 위해서 Dockerfile
내부의 RUN 명령어로 미리 삽입할 것이다.
app.name
이나 master loca[4]
는 이 troubleshooting 내용과 무관하게 그냥 custom 목적으로 설정해둔 것이니 이 부분은 사용하지 않아도 좋다. 중요한 것은 spark-default.conf를 새로 만들어서 copy하거나 덮어씌우지 말고 기존에 있는 파일이 컨테이너 내부에 이미 존재하고 있으니 그 파일에 append를 아래와 같이 한다는 점이다. 설정 항목은 extraJavaOptions
이고 대상은 Djavax.net.ssl.trustStore
변수이다.executor
와 driver
모두 설정해야 하는 점이 중요하다. RUN echo "spark.app.name MySparkApp" >> $SPARK_CONF_DIR/spark-defaults.conf && \
echo "spark.master local[4]" >> $SPARK_CONF_DIR/spark-defaults.conf && \
echo "spark.executor.extraJavaOptions -Djavax.net.ssl.trustStore=/home/glue_user/.certs/container_certs/keystore.jks -Djavax.net.ssl.trustStorePassword=changeit" >> $SPARK_CONF_DIR/spark-defaults.conf && \
echo "spark.driver.extraJavaOptions -Djavax.net.ssl.trustStore=/home/glue_user/.certs/container_certs/keystore.jks -Djavax.net.ssl.trustStorePassword=changeit" >> $SPARK_CONF_DIR/spark-defaults.conf
FROM amazon/aws-glue-libs:glue_libs_3.0.0_image_01
WORKDIR /home/glue_user/workspace/glue
ENTRYPOINT ["bash"]
USER root
COPY 사설인증서.crt /home/glue_user/aws_helper/
RUN mkdir -p /home/glue_user/.certs/container_certs
RUN keytool -import -trustcacerts -keystore /home/glue_user/.certs/container_certs/keystore.jks -storepass changeit -alias mycert -noprompt -file /home/glue_user/aws_helper/사설인증서.crt
# Append new configuration to spark-defaults.conf
RUN echo "spark.app.name MySparkApp" >> $SPARK_CONF_DIR/spark-defaults.conf && \
echo "spark.master local[4]" >> $SPARK_CONF_DIR/spark-defaults.conf && \
echo "spark.executor.extraJavaOptions -Djavax.net.ssl.trustStore=/home/glue_user/.certs/container_certs/keystore.jks -Djavax.net.ssl.trustStorePassword=changeit" >> $SPARK_CONF_DIR/spark-defaults.conf && \
echo "spark.driver.extraJavaOptions -Djavax.net.ssl.trustStore=/home/glue_user/.certs/container_certs/keystore.jks -Djavax.net.ssl.trustStorePassword=changeit" >> $SPARK_CONF_DIR/spark-defaults.conf
#부가 패키지
RUN pip3 install awswrangler
USER glue_user
WORKDIR /home/glue_user/workspace
이제 끝났다. Glue 로컬 개발을 시작해보자.