AWS는 복잡한 것도 있지만... 잘못하면 과금 될 수 있어서 조심해야 한다.
나는 예전에 실습하다가 EC2 인스턴스를 두 개 이상 켜놓고 안 꺼서 요금이 청구된 적 있다.
무려 20달러나....
그렇게 많은 돈은 아니지만 소득이 없는 사람에게는 큰 금액이었다. 다행스럽게도 이메일로 반성문을 제출했더니 환불받을 수 있었다. (적은 금액은 그래도 돌려준다.) 그뒤로 무서워서 얼씬도 하지 않았지만 이번에 이미지 업로드를 위해 S3를 이용해보았다. 어쨌뜬 AWS를 이용할 때는 과금이 발생하지 않도록 설정에 주의하고, 과금 알림을 설정해놓고 메일을 잘 체크하자.
{
"Id": "Policy1658663882176",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1658663877057",
"Action": [
"s3:DeleteObject",
"s3:GetObject",
"s3:PutObject"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::${BucketName}/",
"Principal": "*"
}
]
}
정책 설정에 들어가서 이처럼 json으로 설정을 넣는다
BucketName에 자신의 Bucket이름을 쓴다
그리고 IAM 유저 추가해서 AmazonS3FullAccess
권한을 준 뒤 액세스 키와 시크릿 키를 복사하고 절대 외부에 노출되는 일이 없게 하자
나는 프로젝트 .env
파일에 환경변수로 추가할 것이다.
이제 여기다 올려야 됨.
지난번 글에서는 이제 서버 폴더에다 이미지를 업로드했는데 여기서 사용했던 multer
를 이번에도 쓴다. 그런데 다른 점은 s3에 업로드 하기 위해 multer-s3
도 설치한다는 것. 그리고 sdk도 설치할 건데 주의할 점은 multer-s3
가 2.0 버전이면 sdk도 2.0버전을, 3.0이면 3.0버전을 써야 한다는 것이다. 지금은 multer-s3을 설치하면 자동으로 3버전이 설치될 건데 인터넷 자료를 참고하면 aws sdk를 2.0 버전을 쓰는 것들이 있어서 오류가 날 수 있음. 물론 multer-s3을 설치하면 콘솔에 의존성 관련해서 친절하게 알려준다. 이 글에서의 버전.
"@aws-sdk/abort-controller": "^3.127.0",
"@aws-sdk/client-s3": "^3.135.0",
"multer": "^1.4.5-lts.1",
"multer-s3": "^3.0.1",
$ yarn add @aws-sdk/abort-controller @aws-sdk/client-s3 multer multer-s3
import dotenv from 'dotenv';
import { S3Client } from '@aws-sdk/client-s3';
dotenv.config();
const s3 = new S3Client({
region: 'ap-northeast-2',
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY,
secretAccessKey: process.env.S3_ACCESS_SECRET,
},
});
export default s3;
클라이언트 객체를 만든다.
import dotenv from 'dotenv';
import multer from 'multer';
import multerS3 from 'multer-s3';
import s3 from '../config/s3.js';
dotenv.config();
const uploadImage = multer({
storage: multerS3({
s3,
bucket: process.env.S3_BUCKET_NAME,
contentType: multerS3.AUTO_CONTENT_TYPE,
key: function (req, file, cb) {
cb(null, `${Date.now()}_${file.originalname}`);
},
}),
limits: { fileSize: 1 * 1024 * 1024 },
});
export default uploadImage;
router.post('/upload', uploadImage.single('img'), async (req, res, next) => {
//이미지 업로드함
const { id } = req.decoded;
await member.update(
{
profile_image: req.file.location,
},
{ where: { id } }
);
res.send(req.file.location);
} catch (err) {
console.error(err);
next(err);
}
});
이미지를 업로드하고 url을 db에 저장한다.
아주 간단하다.
const [image, setImage] = useState("");
const [imageUrl, setImageUrl] = useState("");
<form onSubmit={onSubmit}>
{imageUrl ? (
<>
<img src={imageUrl} alt="" width={50} />
</>
) : (
""
)}
<input type="file" onChange={onChange} />
<button type="submit">업로드</button>
</form>
const onChange = (e) => {
setImage(e.target.files[0]);
};
const onSubmit = async (e) => {
e.preventDefault();
try {
const formData = new FormData();
formData.append("img", image);
const res = await axios.post("http://localhost:3001/api/image/upload", formData);
alert("업로드 성공!");
setImageUrl(res.data);
} catch (err) {
console.error(err);
}
};
그러면 이미지가 업로드되고 이렇게 표시된다
이제 변경된 프로필 이미지가 표시된다